Changeset 21315


Ignore:
Timestamp:
10/26/16 15:18:21 (8 years ago)
Author:
Mathieu Morlighem
Message:

CHG: new version of export_fig with a patch

Location:
issm/trunk-jpl/externalpackages/export_fig
Files:
3 added
15 edited

Legend:

Unmodified
Added
Removed
  • issm/trunk-jpl/externalpackages/export_fig/LICENSE

    r19993 r21315  
    1 Copyright (c) 2014, Oliver J. Woodford
     1Copyright (c) 2014, Oliver J. Woodford, Yair M. Altman
    22All rights reserved.
    33
  • issm/trunk-jpl/externalpackages/export_fig/README.md

    r19993 r21315  
    2525|![](https://farm6.staticflickr.com/5616/15589249291_16e485c29a_o_d.png)|![](https://farm4.staticflickr.com/3944/15406302850_4d2e1c7afa_o_d.png)|![](https://farm6.staticflickr.com/5607/15568225476_8ce9bd5f6b_o_d.png)|
    2626
    27 Note that the size and background colour of test2.png (the output of export_fig) are the same as those of the on screen figure, in contrast to test.png. Of course, if you want want the figure background to be white (or any other colour) in the exported file then you can set this prior to exporting using:
     27Note that the size and background colour of test2.png (the output of export_fig) are the same as those of the on screen figure, in contrast to test.png. Of course, if you want the figure background to be white (or any other colour) in the exported file then you can set this prior to exporting using:
    2828```Matlab
    2929set(gcf, 'Color', 'w');
     
    149149**Cropping** - by default, export_fig crops its output to minimize the amount of empty space around the figure. If you'd prefer the figure to be uncropped, and instead have the same appearance (in terms of border width) as the on screen figure, then use the `-nocrop` option. 
    150150 
    151 **Colourspace** - by default, export_fig generates files in the RGB [colourspace](http://en.wikipedia.org/wiki/Color_space). However, you can also export in greyscale or the CMYK colourspace, using the `-grey` (or `-gray`) and `-cmyk` options respectively. The CMYK option is useful for publishers who require documents in this colourspace, but the option is only supported for PDF, EPS and TIFF files.
     151**Colourspace** - by default, export_fig generates files in the RGB [colourspace](https://en.wikipedia.org/wiki/Color_space). However, you can also export in greyscale or the CMYK colourspace, using the `-grey` (or `-gray`) and `-cmyk` options respectively. The CMYK option is useful for publishers who require documents in this colourspace, but the option is only supported for PDF, EPS and TIFF files.
    152152
    153153**Specifying a target directory** - you can get export_fig to save output files to any directory (for which you have write permission), simply by specifying the full or relative path in the filename. For example:
     
    171171**Specifying the figure/axes** - if you have mutiple figures open you can specify which figure to export using its handle: 
    172172```Matlab
    173 export_fig(figure_handle, 'filename.fmt');
     173export_fig(figure_handle, filename);
    174174```
    175175Equally, if your figure contains several subplots then you can export just one of them by giving export_fig the handle to the relevant axes:
    176176```Matlab
    177 export_fig(axes_handle, 'filename.fmt');
     177export_fig(axes_handle, filename);
    178178```
    179179
     
    195195**Appending to a file** - you can use the `-append` option to append the figure to the end of an image/document, if it already exists. This is supported for PDF and TIFF files only. Note that if you wish to append a lot of figures consecutively to a PDF, it can be more efficient to save all the figures to PDF separately then append them all in one go at the end (e.g. using [append_pdfs](http://www.mathworks.com/matlabcentral/fileexchange/31215-appendpdfs)). 
    196196 
     197**Output to clipboard** - you can use the `-clipboard` option to copy the specified figure or axes to the system clipboard, for easy paste into other documents (e.g., Word or PowerPoint). Note that the image is copied in bitmap (not vector) format. 
     198 
    197199**Font size** - if you want to place an exported figure in a document with the font a particular size then you need to set the font to that size in the figure, and not resize the output of export_fig in the document. To avoid resizing, simply make sure that the on screen figure is the size you want the output to be in the document before exporting. 
    198200 
    199 **Renderers** - MATLAB has three renderers for displaying and exporting figures: painters, OpenGL and ZBuffer. The different renderers have different [features](http://www.mathworks.com/access/helpdesk/help/techdoc/creating_plots/f3-84337.html#f3-102410), so if you aren't happy with the result from one renderer try another. By default, vector formats (i.e. PDF and EPS outputs) use the painters renderer, while other formats use the OpenGL renderer. Non-default renderers can be selected by using one of these three export_fig input options: `-painters`, `-opengl`, `-zbuffer`. 
     201**Renderers** - MATLAB has three renderers for displaying and exporting figures: painters, OpenGL and ZBuffer. The different renderers have different [features](http://www.mathworks.com/access/helpdesk/help/techdoc/creating_plots/f3-84337.html#f3-102410), so if you aren't happy with the result from one renderer try another. By default, vector formats (i.e. PDF and EPS outputs) use the painters renderer, while other formats use the OpenGL renderer. Non-default renderers can be selected by using one of these three export_fig input options: `-painters`, `-opengl`, `-zbuffer`: 
     202```Matlab
     203export_fig test.png -painters
     204```
    200205 
    201206**Artifacts** - sometimes the output that you get from export_fig is not what you expected. If an output file contains artifacts that aren't in the on screen figure then make sure that the renderer used for rendering the figure on screen is the same as that used for exporting. To set the renderer used to display the figure, use: 
     
    215220
    216221**Undefined function errors** - If you download and run export_fig and get an error similar to this: 
    217 ```Matlab
     222```
    218223??? Undefined function or method 'print2array' for input arguments of type 'double'.
    219224```
     
    221226 
    222227### Known issues
    223 There are lots of problems with MATLAB's exporting functions, and unfortunately export_fig, which is simply a glorified wrapper for MATLAB's print function, doesn't solve all of them (yet?). Some of the problems I know about are:
    224  
    225 **Fonts** - when using the painters renderer, MATLAB can only export a small number of fonts, details of which can be found [here](http://www.mathworks.com/access/helpdesk/help/techdoc/creating_plots/f3-103191.html#f3-96545). Export_fig attempts to correct font names in the resulting EPS file (for upto a maximum of 11 different fonts in one figure), but this is not always guaranteed to work. In particular, the text positions will be affected. It also does not work for text blocks where the 'Interpreter' property is set to 'latex'.
    226 
    227 Also, when using the painters renderer, ghostscript will sometimes throw an error such as `Error: /undefined in /findfont`. This suggests that ghostscript could not find a definition file for one of your fonts. One possible fix for this is to make sure the file `EXPORT_FIG_PATH/.ignore/gs_font_path.txt` exists and contains a list of paths to the folder(s) containing the necessary font definitions (make sure they're TrueType definitions), separated by a semicolon.
    228 
    229 **RGB color data not yet supported in Painter's mode** - you will see this as a warning if you try to export a figure which contains patch objects whose face or vertex colors are specified as a an RGB colour, rather than an index into the colormap, using the painters renderer (the default renderer for vector output). This problem can arise if you use `pcolor`, for example. This is a problem with MATLAB's painters renderer, which also affects `print`; there is currently no fix available in export_fig (other than to export to bitmap). The suggested workaround is to avoid colouring patches using RGB. First, try to use colours in the figure's colourmap (instructions [here](http://www.mathworks.co.uk/support/solutions/en/data/1-6OTPQE/)) - change the colourmap, if necessary. If you are using `pcolor`, try using [uimagesc](http://www.mathworks.com/matlabcentral/fileexchange/11368) (on the file exchange) instead. 
     228There are lots of problems with MATLAB's exporting functions, especially `print`. Export_fig is simply a glorified wrapper for MATLAB's `print` function, and doesn't solve all of its bugs (yet?). Some of the problems I know about are:
     229 
     230**Fonts** - when using the painters renderer, MATLAB can only export a small number of fonts, details of which can be found [here](http://www.mathworks.com/help/releases/R2014a/matlab/creating_plots/choosing-a-printer-driver.html#f3-96545). Export_fig attempts to correct font names in the resulting EPS file (up to a maximum of 11 different fonts in one figure), but this is not always guaranteed to work. In particular, the text positions will be affected. It also does not work for text blocks where the 'Interpreter' property is set to 'latex'.
     231
     232Also, when using the painters renderer, ghostscript will sometimes throw an error such as `Error: /undefined in /findfont`. This suggests that ghostscript could not find a definition file for one of your fonts. One possible fix for this is to make sure the file `EXPORT_FIG_PATH/.ignore/gs_font_path.txt` exists and contains a list of paths to the folder(s) containing the necessary font definitions (make sure that they are TrueType definitions!), separated by a semicolon.
     233
     234**RGB color data not yet supported in Painter's mode** - you will see this as a warning if you try to export a figure which contains patch objects whose face or vertex colors are specified as an RGB colour, rather than an index into the colormap, using the painters renderer (the default renderer for vector output). This problem can arise if you use `pcolor`, for example. This is a problem with MATLAB's painters renderer, which also affects `print`; there is currently no fix available in export_fig (other than to export to bitmap). The suggested workaround is to avoid colouring patches using RGB. First, try to use colours in the figure's colourmap (instructions [here](http://www.mathworks.co.uk/support/solutions/en/data/1-6OTPQE/)) - change the colourmap, if necessary. If you are using `pcolor`, try using [uimagesc](http://www.mathworks.com/matlabcentral/fileexchange/11368) (on the file exchange) instead. 
    230235
    231236**Dashed contour lines appear solid** - when using the painters renderer, MATLAB cannot generate dashed lines using the `contour` function (either on screen or in exported PDF and EPS files). Details can be found [here](http://www.mathworks.com/support/solutions/en/data/1-14PPHB/?solution=1-14PPHB). 
     
    233238**Text size** - when using the OpenGL or ZBuffer renderers, large text can be resized relative to the figure when exporting at non-screen-resolution (including using anti-alising at screen resolution). This is a feature of MATLAB's `print `function. In this case, try using the `-painters` option. 
    234239 
    235 **Lighting and transparency** - when using the painters renderer, transparency and lighting effects are not supported. Sorry, but this is a feature of the renderer. To find out more about the capabilities of each rendering method, see [here](http://www.mathworks.com/access/helpdesk/help/techdoc/creating_plots/f3-84337.html#f3-102410). You can still export transparent objects to vector format (SVG) using the excellent [plot2svg](http://www.mathworks.com/matlabcentral/fileexchange/7401) package, then convert this to PDF, for example using [Inkscape](http://inkscape.org/). However, it can't handle lighting. 
    236  
    237 **Lines in patch objects** - when exporting patch objects to PDF using the painters renderer (default), sometimes the output can appear to have lines across the middle of rectangular patches; these lines are the colour of the background, as if there is a crack in the patch, allowing you to see through. This issue is a feature of the software used to display the PDF, rather than the PDF itself. Sometimes disabling anti-aliasing in this software can get rid of the lines
     240**Lighting and transparency** - when using the painters renderer, transparency and lighting effects are not supported. Sorry, but this is an inherent feature of MATLAB's painters renderer. To find out more about the capabilities of each rendering method, see [here](http://www.mathworks.com/access/helpdesk/help/techdoc/creating_plots/f3-84337.html#f3-102410). You can still export transparent objects to vector format (SVG) using the excellent [plot2svg](http://www.mathworks.com/matlabcentral/fileexchange/7401) package, then convert this to PDF, for example using [Inkscape](http://inkscape.org/). However, it can't handle lighting. 
     241 
     242**Lines in patch objects** - when exporting patch objects to PDF using the painters renderer (default), sometimes the output can appear to have lines across the middle of rectangular patches; these lines are the colour of the background, as if there is a crack in the patch, allowing you to see through. This appears to be due to bugs in MATLAB's internal vector rendering code. These lines can often be removed from the PDF using software such as [InkScape](https://inkscape.org). Sometimes disabling anti-aliasing in the PDF-reader software can get rid of the lines ([discussion](https://github.com/altmany/export_fig/issues/44))
    238243 
    239244**Out of memory** - if you run into memory issues when using export_fig, some ways to get round this are: 
    240245 1. Reduce the level of anti-aliasing.
    241  2. Reduce the size of the on screen figure.
    242  3. Reduce the resolution (dpi) the figure is exported at. 
     246 2. Reduce the size of the figure.
     247 3. Reduce the export resolution (dpi).
     248 4. Change the renderer to painters or ZBuffer. 
    243249 
    244250**Errors** - the other common type of errors people get with export_fig are OpenGL errors. This isn't a fault of export_fig, but either a bug in MATLAB's `print`, or your graphics driver getting itself into a state. Always make sure your graphics driver is up-to-date. If it still doesn't work, try using the ZBuffer renderer. 
     
    249255Secondly, if exporting to bitmap, do try all the renderers (i.e. try the options `-opengl`, `-zbuffer` and `-painters` separately), to see if one of them does produce an acceptable output, and if so, use that.
    250256
    251 If the figure looks correct on screen, but an error exists in the exported output (which cannot be solved using a different renderer) then please feel free to raise an [issue](https://github.com/ojwoodford/export_fig/issues). Please be sure to include the .fig file, the export_fig command you use, the output you get, and a description of what you expected. I can't promise anything, but if it's easy to fix I probably will do it. Often I will find that the error is due to a bug in MATLAB's print function, in which case I will suggest you submit it as a bug to TheMathWorks, and inform me of any fix they suggest. Also, if there's a feature you'd like that isn't supported please tell me what it is and I'll consider implementing it.
     257If this still does not help, then ensure that you are using the latest version of export_fig, which is available [here](https://github.com/altmany/export_fig/archive/master.zip). 
     258 
     259If the figure looks correct on screen, but an error exists in the exported output (which cannot be solved using a different renderer) then please feel free to raise an [issue](https://github.com/altmany/export_fig/issues). Please be sure to include the .fig file, the export_fig command you use, the output you get, and a description of what you expected. I can't promise anything, but if it's easy to fix I may indeed do it. Often I will find that the error is due to a bug in MATLAB's `print` function, in which case I will suggest you submit it as a bug to TheMathWorks, and inform me of any fix they suggest. Also, if there's a feature you'd like that isn't supported please tell me what it is and I'll consider implementing it.
    252260
    253261### And finally...
     
    255263![](https://farm4.staticflickr.com/3956/15591911455_b9008bd77e_o_d.jpg)
    256264
    257 If you've ever wondered what's going on in the icon on the export_fig download page (reproduced on the left), then this explanantion is for you. The icon is designed to demonstrate as many of export_fig's features as possible. Given a
    258 figure containing a translucent mesh (top right), export_fig can export to pdf (bottom centre), which allows the figure to be zoomed in without losing quality (because it's a vector graphic), but isn't able to reproduce the translucency, and also, depending on the viewer, creates small gaps between the patches, which are seen here as thin white lines. By contrast, when exporting to png (top left), translucency is preserved (see how the graphic below shows through), the figure is anti-aliased, but zooming in does not reveal more detail.
    259 
     265If you've ever wondered what's going on in the logo on the export_fig download page (reproduced here), then this explanantion is for you. The logo is designed to demonstrate as many of export_fig's features as possible:
     266 
     267Given a figure containing a translucent mesh (top right), export_fig can export to pdf (bottom centre), which allows the figure to be zoomed-in without losing quality (because it's a vector graphic), but isn't able to reproduce the translucency. Also, depending on the PDF viewer program, small gaps appear between the patches, which are seen here as thin white lines.
     268 
     269By contrast, when exporting to png (top left), translucency is preserved (see how the graphic below shows through), and the figure is anti-aliased. However, zooming-in does not reveal more detail since png is a bitmap format. Also, lines appear less sharp than in the pdf output.
     270
  • issm/trunk-jpl/externalpackages/export_fig/append_pdfs.m

    r19993 r21315  
    3333% setting
    3434
     35% 26/02/15: If temp dir is not writable, use the output folder for temp
     36%           files when appending (Javier Paredes); sanity check of inputs
     37
    3538function append_pdfs(varargin)
     39
     40if nargin < 2,  return;  end  % sanity check
     41
    3642% Are we appending or creating a new file
    3743append = exist(varargin{1}, 'file') == 2;
    38 if append
    39     output = [tempname '.pdf'];
    40 else
     44output = [tempname '.pdf'];
     45try
     46    % Ensure that the temp dir is writable (Javier Paredes 26/2/15)
     47    fid = fopen(output,'w');
     48    fwrite(fid,1);
     49    fclose(fid);
     50    delete(output);
     51    isTempDirOk = true;
     52catch
     53    % Temp dir is not writable, so use the output folder
     54    [dummy,fname,fext] = fileparts(output); %#ok<ASGLU>
     55    fpath = fileparts(varargin{1});
     56    output = fullfile(fpath,[fname fext]);
     57    isTempDirOk = false;
     58end
     59if ~append
    4160    output = varargin{1};
    4261    varargin = varargin(2:end);
    4362end
    4463% Create the command file
    45 cmdfile = [tempname '.txt'];
     64if isTempDirOk
     65    cmdfile = [tempname '.txt'];
     66else
     67    cmdfile = fullfile(fpath,[fname '.txt']);
     68end
    4669fh = fopen(cmdfile, 'w');
    4770fprintf(fh, '-q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -sOutputFile="%s" -f', output);
  • issm/trunk-jpl/externalpackages/export_fig/copyfig.m

    r19993 r21315  
     1function fh = copyfig(fh)
    12%COPYFIG Create a copy of a figure, without changing the figure
    23%
     
    1516% Copyright (C) Oliver Woodford 2012
    1617
    17 function fh = copyfig(fh)
    18 % Set the default
    19 if nargin == 0
    20     fh = gcf;
     18% 26/02/15: If temp dir is not writable, use the dest folder for temp
     19%           destination files (Javier Paredes)
     20% 15/04/15: Suppress warnings during copyobj (Dun Kirk comment on FEX page 2013-10-02)
     21
     22    % Set the default
     23    if nargin == 0
     24        fh = gcf;
     25    end
     26    % Is there a legend?
     27    if isempty(findall(fh, 'Type', 'axes', 'Tag', 'legend'))
     28        % Safe to copy using copyobj
     29        oldWarn = warning('off'); %#ok<WNOFF>  %Suppress warnings during copyobj (Dun Kirk comment on FEX page 2013-10-02)
     30        fh = copyobj(fh, 0);
     31        warning(oldWarn);
     32    else
     33        % copyobj will change the figure, so save and then load it instead
     34        tmp_nam = [tempname '.fig'];
     35        try
     36            % Ensure that the temp dir is writable (Javier Paredes 26/2/15)
     37            fid = fopen(tmp_nam,'w');
     38            fwrite(fid,1);
     39            fclose(fid);
     40            delete(tmp_nam);  % cleanup
     41        catch
     42            % Temp dir is not writable, so use the current folder
     43            [dummy,fname,fext] = fileparts(tmp_nam); %#ok<ASGLU>
     44            fpath = pwd;
     45            tmp_nam = fullfile(fpath,[fname fext]);
     46        end
     47        hgsave(fh, tmp_nam);
     48        fh = hgload(tmp_nam);
     49        delete(tmp_nam);
     50    end
    2151end
    22 % Is there a legend?
    23 if isempty(findall(fh, 'Type', 'axes', 'Tag', 'legend'))
    24     % Safe to copy using copyobj
    25     fh = copyobj(fh, 0);
    26 else
    27     % copyobj will change the figure, so save and then load it instead
    28     tmp_nam = [tempname '.fig'];
    29     hgsave(fh, tmp_nam);
    30     fh = hgload(tmp_nam);
    31     delete(tmp_nam);
    32 end
    33 end
  • issm/trunk-jpl/externalpackages/export_fig/crop_borders.m

    r19993 r21315  
     1function [A, vA, vB, bb_rel] = crop_borders(A, bcol, padding, crop_amounts)
    12%CROP_BORDERS Crop the borders of an image or stack of images
    23%
    3 %   [B, v] = crop_borders(A, bcol, [padding])
     4%   [B, vA, vB, bb_rel] = crop_borders(A, bcol, [padding])
    45%
    56%IN:
    67%   A - HxWxCxN stack of images.
    78%   bcol - Cx1 background colour vector.
    8 %   padding - scalar indicating how many pixels padding to have. Default: 0.
     9%   padding - scalar indicating how much padding to have in relation to
     10%             the cropped-image-size (0<=padding<=1). Default: 0
     11%   crop_amounts - 4-element vector of crop amounts: [top,right,bottom,left]
     12%             where NaN/Inf indicate auto-cropping, 0 means no cropping,
     13%             and any other value mean cropping in pixel amounts.
    914%
    1015%OUT:
    1116%   B - JxKxCxN cropped stack of images.
    12 %   v - 1x4 vector of start and end indices for first two dimensions, s.t.
    13 %       B = A(v(1):v(2),v(3):v(4),:,:).
     17%   vA     - coordinates in A that contain the cropped image
     18%   vB     - coordinates in B where the cropped version of A is placed
     19%   bb_rel - relative bounding box (used for eps-cropping)
    1420
    15 function [A, v] = crop_borders(A, bcol, padding)
    16 if nargin < 3
    17     padding = 0;
    18 end
    19 [h, w, c, n] = size(A);
    20 if isscalar(bcol)
    21     bcol = bcol(ones(c, 1));
    22 end
    23 bail = false;
    24 for l = 1:w
    25     for a = 1:c
    26         if ~all(col(A(:,l,a,:)) == bcol(a))
    27             bail = true;
    28             break;
     21%{
     22% 06/03/15: Improved image cropping thanks to Oscar Hartogensis
     23% 08/06/15: Fixed issue #76: case of transparent figure bgcolor
     24% 21/02/16: Enabled specifying non-automated crop amounts
     25% 04/04/16: Fix per Luiz Carvalho for old Matlab releases
     26% 23/10/16: Fixed issue #175: there used to be a 1px minimal padding in case of crop, now removed
     27%}
     28
     29    if nargin < 3
     30        padding = 0;
     31    end
     32    if nargin < 4
     33        crop_amounts = nan(1,4);  % =auto-cropping
     34    end
     35    crop_amounts(end+1:4) = NaN;  % fill missing values with NaN
     36
     37    [h, w, c, n] = size(A);
     38    if isempty(bcol)  % case of transparent bgcolor
     39        bcol = A(ceil(end/2),1,:,1);
     40    end
     41    if isscalar(bcol)
     42        bcol = bcol(ones(c, 1));
     43    end
     44
     45    % Crop margin from left
     46    if ~isfinite(crop_amounts(4))
     47        bail = false;
     48        for l = 1:w
     49            for a = 1:c
     50                if ~all(col(A(:,l,a,:)) == bcol(a))
     51                    bail = true;
     52                    break;
     53                end
     54            end
     55            if bail
     56                break;
     57            end
    2958        end
     59    else
     60        l = 1 + abs(crop_amounts(4));
    3061    end
    31     if bail
    32         break;
     62
     63    % Crop margin from right
     64    if ~isfinite(crop_amounts(2))
     65        bcol = A(ceil(end/2),w,:,1);
     66        bail = false;
     67        for r = w:-1:l
     68            for a = 1:c
     69                if ~all(col(A(:,r,a,:)) == bcol(a))
     70                    bail = true;
     71                    break;
     72                end
     73            end
     74            if bail
     75                break;
     76            end
     77        end
     78    else
     79        r = w - abs(crop_amounts(2));
    3380    end
    34 end
    35 bcol = A(ceil(end/2),w,:,1);
    36 bail = false;
    37 for r = w:-1:l
    38     for a = 1:c
    39         if ~all(col(A(:,r,a,:)) == bcol(a))
    40             bail = true;
    41             break;
     81
     82    % Crop margin from top
     83    if ~isfinite(crop_amounts(1))
     84        bcol = A(1,ceil(end/2),:,1);
     85        bail = false;
     86        for t = 1:h
     87            for a = 1:c
     88                if ~all(col(A(t,:,a,:)) == bcol(a))
     89                    bail = true;
     90                    break;
     91                end
     92            end
     93            if bail
     94                break;
     95            end
    4296        end
     97    else
     98        t = 1 + abs(crop_amounts(1));
    4399    end
    44     if bail
    45         break;
     100
     101    % Crop margin from bottom
     102    bcol = A(h,ceil(end/2),:,1);
     103    if ~isfinite(crop_amounts(3))
     104        bail = false;
     105        for b = h:-1:t
     106            for a = 1:c
     107                if ~all(col(A(b,:,a,:)) == bcol(a))
     108                    bail = true;
     109                    break;
     110                end
     111            end
     112            if bail
     113                break;
     114            end
     115        end
     116    else
     117        b = h - abs(crop_amounts(3));
    46118    end
    47 end
    48 bcol = A(1,ceil(end/2),:,1);
    49 bail = false;
    50 for t = 1:h
    51     for a = 1:c
    52         if ~all(col(A(t,:,a,:)) == bcol(a))
    53             bail = true;
    54             break;
     119
     120    if padding == 0  % no padding
     121        % Issue #175: there used to be a 1px minimal padding in case of crop, now removed
     122        %{
     123        if ~isequal([t b l r], [1 h 1 w]) % Check if we're actually croppping
     124            padding = 1; % Leave one boundary pixel to avoid bleeding on resize
     125            bcol(:) = nan;  % make the 1px padding transparent
    55126        end
     127        %}
     128    elseif abs(padding) < 1  % pad value is a relative fraction of image size
     129        padding = sign(padding)*round(mean([b-t r-l])*abs(padding)); % ADJUST PADDING
     130    else  % pad value is in units of 1/72" points
     131        padding = round(padding);  % fix cases of non-integer pad value
    56132    end
    57     if bail
    58         break;
     133
     134    if padding > 0  % extra padding
     135        % Create an empty image, containing the background color, that has the
     136        % cropped image size plus the padded border
     137        B = repmat(bcol,[(b-t)+1+padding*2,(r-l)+1+padding*2,1,n]);  % Fix per Luiz Carvalho
     138        % vA - coordinates in A that contain the cropped image
     139        vA = [t b l r];
     140        % vB - coordinates in B where the cropped version of A will be placed
     141        vB = [padding+1, (b-t)+1+padding, padding+1, (r-l)+1+padding];
     142        % Place the original image in the empty image
     143        B(vB(1):vB(2), vB(3):vB(4), :, :) = A(vA(1):vA(2), vA(3):vA(4), :, :);
     144        A = B;
     145    else  % extra cropping
     146        vA = [t-padding b+padding l-padding r+padding];
     147        A = A(vA(1):vA(2), vA(3):vA(4), :, :);
     148        vB = [NaN NaN NaN NaN];
    59149    end
    60 end
    61 bcol = A(h,ceil(end/2),:,1);
    62 bail = false;
    63 for b = h:-1:t
    64     for a = 1:c
    65         if ~all(col(A(b,:,a,:)) == bcol(a))
    66             bail = true;
    67             break;
    68         end
    69     end
    70     if bail
    71         break;
    72     end
    73 end
    74 % Crop the background, leaving one boundary pixel to avoid bleeding on resize
    75 v = [max(t-padding, 1) min(b+padding, h) max(l-padding, 1) min(r+padding, w)];
    76 A = A(v(1):v(2),v(3):v(4),:,:);
     150
     151    % For EPS cropping, determine the relative BoundingBox - bb_rel
     152    bb_rel = [l-1 h-b-1 r+1 h-t+1]./[w h w h];
    77153end
    78154
    79155function A = col(A)
    80 A = A(:);
     156    A = A(:);
    81157end
  • issm/trunk-jpl/externalpackages/export_fig/eps2pdf.m

    r19993 r21315  
     1function eps2pdf(source, dest, crop, append, gray, quality, gs_options)
    12%EPS2PDF  Convert an eps file to pdf format using ghostscript
    23%
     
    78%   eps2pdf(source, dest, crop, append, gray)
    89%   eps2pdf(source, dest, crop, append, gray, quality)
     10%   eps2pdf(source, dest, crop, append, gray, quality, gs_options)
    911%
    1012% This function converts an eps file to pdf format. The output can be
     
    1719% system. Ghostscript can be downloaded from: http://www.ghostscript.com
    1820%
    19 %IN:
    20 %   source - filename of the source eps file to convert. The filename is
    21 %            assumed to already have the extension ".eps".
    22 %   dest - filename of the destination pdf file. The filename is assumed to
    23 %          already have the extension ".pdf".
    24 %   crop - boolean indicating whether to crop the borders off the pdf.
    25 %          Default: true.
    26 %   append - boolean indicating whether the eps should be appended to the
    27 %            end of the pdf as a new page (if the pdf exists already).
    28 %            Default: false.
    29 %   gray - boolean indicating whether the output pdf should be grayscale or
    30 %          not. Default: false.
     21% Inputs:
     22%   source  - filename of the source eps file to convert. The filename is
     23%             assumed to already have the extension ".eps".
     24%   dest    - filename of the destination pdf file. The filename is assumed
     25%             to already have the extension ".pdf".
     26%   crop    - boolean indicating whether to crop the borders off the pdf.
     27%             Default: true.
     28%   append  - boolean indicating whether the eps should be appended to the
     29%             end of the pdf as a new page (if the pdf exists already).
     30%             Default: false.
     31%   gray    - boolean indicating whether the output pdf should be grayscale
     32%             or not. Default: false.
    3133%   quality - scalar indicating the level of image bitmap quality to
    3234%             output. A larger value gives a higher quality. quality > 100
    3335%             gives lossless output. Default: ghostscript prepress default.
     36%   gs_options - optional ghostscript options (e.g.: '-dNoOutputFonts'). If
     37%                multiple options are needed, enclose in call array: {'-a','-b'}
    3438
    35 % Copyright (C) Oliver Woodford 2009-2011
     39% Copyright (C) Oliver Woodford 2009-2014, Yair Altman 2015-
    3640
    3741% Suggestion of appending pdf files provided by Matt C at:
     
    4448
    4549% 9/12/2011 Pass font path to ghostscript.
     50% 26/02/15: If temp dir is not writable, use the dest folder for temp
     51%           destination files (Javier Paredes)
     52% 28/02/15: Enable users to specify optional ghostscript options (issue #36)
     53% 01/03/15: Upon GS error, retry without the -sFONTPATH= option (this might solve
     54%           some /findfont errors according to James Rankin, FEX Comment 23/01/15)
     55% 23/06/15: Added extra debug info in case of ghostscript error; code indentation
     56% 04/10/15: Suggest a workaround for issue #41 (missing font path; thanks Mariia Fedotenkova)
     57% 22/02/16: Bug fix from latest release of this file (workaround for issue #41)
    4658
    47 function eps2pdf(source, dest, crop, append, gray, quality)
    48 % Intialise the options string for ghostscript
    49 options = ['-q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -sOutputFile="' dest '"'];
    50 % Set crop option
    51 if nargin < 3 || crop
    52     options = [options ' -dEPSCrop'];
    53 end
    54 % Set the font path
    55 fp = font_path();
    56 if ~isempty(fp)
    57     options = [options ' -sFONTPATH="' fp '"'];
    58 end
    59 % Set the grayscale option
    60 if nargin > 4 && gray
    61     options = [options ' -sColorConversionStrategy=Gray -dProcessColorModel=/DeviceGray'];
    62 end
    63 % Set the bitmap quality
    64 if nargin > 5 && ~isempty(quality)
    65     options = [options ' -dAutoFilterColorImages=false -dAutoFilterGrayImages=false'];
    66     if quality > 100
    67         options = [options ' -dColorImageFilter=/FlateEncode -dGrayImageFilter=/FlateEncode -c ".setpdfwrite << /ColorImageDownsampleThreshold 10 /GrayImageDownsampleThreshold 10 >> setdistillerparams"'];
     59    % Intialise the options string for ghostscript
     60    options = ['-q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -sOutputFile="' dest '"'];
     61    % Set crop option
     62    if nargin < 3 || crop
     63        options = [options ' -dEPSCrop'];
     64    end
     65    % Set the font path
     66    fp = font_path();
     67    if ~isempty(fp)
     68        options = [options ' -sFONTPATH="' fp '"'];
     69    end
     70    % Set the grayscale option
     71    if nargin > 4 && gray
     72        options = [options ' -sColorConversionStrategy=Gray -dProcessColorModel=/DeviceGray'];
     73    end
     74    % Set the bitmap quality
     75    if nargin > 5 && ~isempty(quality)
     76        options = [options ' -dAutoFilterColorImages=false -dAutoFilterGrayImages=false'];
     77        if quality > 100
     78            options = [options ' -dColorImageFilter=/FlateEncode -dGrayImageFilter=/FlateEncode -c ".setpdfwrite << /ColorImageDownsampleThreshold 10 /GrayImageDownsampleThreshold 10 >> setdistillerparams"'];
     79        else
     80            options = [options ' -dColorImageFilter=/DCTEncode -dGrayImageFilter=/DCTEncode'];
     81            v = 1 + (quality < 80);
     82            quality = 1 - quality / 100;
     83            s = sprintf('<< /QFactor %.2f /Blend 1 /HSample [%d 1 1 %d] /VSample [%d 1 1 %d] >>', quality, v, v, v, v);
     84            options = sprintf('%s -c ".setpdfwrite << /ColorImageDict %s /GrayImageDict %s >> setdistillerparams"', options, s, s);
     85        end
     86    end
     87    % Enable users to specify optional ghostscript options (issue #36)
     88    if nargin > 6 && ~isempty(gs_options)
     89        if iscell(gs_options)
     90            gs_options = sprintf(' %s',gs_options{:});
     91        elseif ~ischar(gs_options)
     92            error('gs_options input argument must be a string or cell-array of strings');
     93        else
     94            gs_options = [' ' gs_options];
     95        end
     96        options = [options gs_options];
     97    end
     98    % Check if the output file exists
     99    if nargin > 3 && append && exist(dest, 'file') == 2
     100        % File exists - append current figure to the end
     101        tmp_nam = tempname;
     102        try
     103            % Ensure that the temp dir is writable (Javier Paredes 26/2/15)
     104            fid = fopen(tmp_nam,'w');
     105            fwrite(fid,1);
     106            fclose(fid);
     107            delete(tmp_nam);
     108        catch
     109            % Temp dir is not writable, so use the dest folder
     110            [dummy,fname,fext] = fileparts(tmp_nam); %#ok<ASGLU>
     111            fpath = fileparts(dest);
     112            tmp_nam = fullfile(fpath,[fname fext]);
     113        end
     114        % Copy the file
     115        copyfile(dest, tmp_nam);
     116        % Add the output file names
     117        options = [options ' -f "' tmp_nam '" "' source '"'];
     118        try
     119            % Convert to pdf using ghostscript
     120            [status, message] = ghostscript(options);
     121        catch me
     122            % Delete the intermediate file
     123            delete(tmp_nam);
     124            rethrow(me);
     125        end
     126        % Delete the intermediate file
     127        delete(tmp_nam);
    68128    else
    69         options = [options ' -dColorImageFilter=/DCTEncode -dGrayImageFilter=/DCTEncode'];
    70         v = 1 + (quality < 80);
    71         quality = 1 - quality / 100;
    72         s = sprintf('<< /QFactor %.2f /Blend 1 /HSample [%d 1 1 %d] /VSample [%d 1 1 %d] >>', quality, v, v, v, v);
    73         options = sprintf('%s -c ".setpdfwrite << /ColorImageDict %s /GrayImageDict %s >> setdistillerparams"', options, s, s);
    74     end
    75 end
    76 % Check if the output file exists
    77 if nargin > 3 && append && exist(dest, 'file') == 2
    78     % File exists - append current figure to the end
    79     tmp_nam = tempname;
    80     % Copy the file
    81     copyfile(dest, tmp_nam);
    82     % Add the output file names
    83     options = [options ' -f "' tmp_nam '" "' source '"'];
    84     try
     129        % File doesn't exist or should be over-written
     130        % Add the output file names
     131        options = [options ' -f "' source '"'];
    85132        % Convert to pdf using ghostscript
    86133        [status, message] = ghostscript(options);
    87     catch me
    88         % Delete the intermediate file
    89         delete(tmp_nam);
    90         rethrow(me);
    91134    end
    92     % Delete the intermediate file
    93     delete(tmp_nam);
    94 else
    95     % File doesn't exist or should be over-written
    96     % Add the output file names
    97     options = [options ' -f "' source '"'];
    98     % Convert to pdf using ghostscript
    99     [status, message] = ghostscript(options);
    100 end
    101 % Check for error
    102 if status
    103     % Report error
    104     if isempty(message)
    105         error('Unable to generate pdf. Check destination directory is writable.');
    106     else
    107         error(message);
     135    % Check for error
     136    if status
     137        % Retry without the -sFONTPATH= option (this might solve some GS
     138        % /findfont errors according to James Rankin, FEX Comment 23/01/15)
     139        orig_options = options;
     140        if ~isempty(fp)
     141            options = regexprep(options, ' -sFONTPATH=[^ ]+ ',' ');
     142            status = ghostscript(options);
     143            if ~status, return; end  % hurray! (no error)
     144        end
     145        % Report error
     146        if isempty(message)
     147            error('Unable to generate pdf. Check destination directory is writable.');
     148        elseif ~isempty(strfind(message,'/typecheck in /findfont'))
     149            % Suggest a workaround for issue #41 (missing font path)
     150            font_name = strtrim(regexprep(message,'.*Operand stack:\s*(.*)\s*Execution.*','$1'));
     151            fprintf(2, 'Ghostscript error: could not find the following font(s): %s\n', font_name);
     152            fpath = fileparts(mfilename('fullpath'));
     153            gs_fonts_file = fullfile(fpath, '.ignore', 'gs_font_path.txt');
     154            fprintf(2, '  try to add the font''s folder to your %s file\n\n', gs_fonts_file);
     155            error('export_fig error');
     156        else
     157            fprintf(2, '\nGhostscript error: perhaps %s is open by another application\n', dest);
     158            if ~isempty(gs_options)
     159                fprintf(2, '  or maybe the%s option(s) are not accepted by your GS version\n', gs_options);
     160            end
     161            fprintf(2, 'Ghostscript options: %s\n\n', orig_options);
     162            error(message);
     163        end
    108164    end
    109 end
    110165end
    111166
    112167% Function to return (and create, where necessary) the font path
    113168function fp = font_path()
    114 fp = user_string('gs_font_path');
    115 if ~isempty(fp)
    116     return
     169    fp = user_string('gs_font_path');
     170    if ~isempty(fp)
     171        return
     172    end
     173    % Create the path
     174    % Start with the default path
     175    fp = getenv('GS_FONTPATH');
     176    % Add on the typical directories for a given OS
     177    if ispc
     178        if ~isempty(fp)
     179            fp = [fp ';'];
     180        end
     181        fp = [fp getenv('WINDIR') filesep 'Fonts'];
     182    else
     183        if ~isempty(fp)
     184            fp = [fp ':'];
     185        end
     186        fp = [fp '/usr/share/fonts:/usr/local/share/fonts:/usr/share/fonts/X11:/usr/local/share/fonts/X11:/usr/share/fonts/truetype:/usr/local/share/fonts/truetype'];
     187    end
     188    user_string('gs_font_path', fp);
    117189end
    118 % Create the path
    119 % Start with the default path
    120 fp = getenv('GS_FONTPATH');
    121 % Add on the typical directories for a given OS
    122 if ispc
    123     if ~isempty(fp)
    124         fp = [fp ';'];
    125     end
    126     fp = [fp getenv('WINDIR') filesep 'Fonts'];
    127 else
    128     if ~isempty(fp)
    129         fp = [fp ':'];
    130     end
    131     fp = [fp '/usr/share/fonts:/usr/local/share/fonts:/usr/share/fonts/X11:/usr/local/share/fonts/X11:/usr/share/fonts/truetype:/usr/local/share/fonts/truetype'];
    132 end
    133 user_string('gs_font_path', fp);
    134 end
  • issm/trunk-jpl/externalpackages/export_fig/export_fig.m

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

    r19993 r21315  
    3838% opened.
    3939
     40% 01/03/15: Issue #20: warn users if using this function in HG2 (R2014b+)
     41% 27/03/15: Fixed out of memory issue with enormous EPS files (generated by print() with OpenGL renderer), related to issue #39
     42
    4043function fstrm = fix_lines(fstrm, fname2)
    4144
     45% Issue #20: warn users if using this function in HG2 (R2014b+)
     46if using_hg2
     47    warning('export_fig:hg2','The fix_lines function should not be used in this Matlab version.');
     48end
     49   
    4250if nargout == 0 || nargin > 1
    4351    if nargin < 2
     
    114122end
    115123
    116 % Isolate line style definition section
    117 first_sec = strfind(fstrm, '% line types:');
    118 [second_sec, remaining] = strtok(fstrm(first_sec+1:end), '/');
    119 [remaining, remaining] = strtok(remaining, '%');
    120 
    121124% Define the new styles, including the new GR format
    122125% Dot and dash lengths have two parts: a constant amount plus a line width
     
    135138
    136139% Construct the output
    137 fstrm = [fstrm(1:first_sec) second_sec sprintf('%s\r', new_style{:}) remaining];
     140% This is the original (memory-intensive) code:
     141%first_sec = strfind(fstrm, '% line types:'); % Isolate line style definition section
     142%[second_sec, remaining] = strtok(fstrm(first_sec+1:end), '/');
     143%[remaining, remaining] = strtok(remaining, '%');
     144%fstrm = [fstrm(1:first_sec) second_sec sprintf('%s\r', new_style{:}) remaining];
     145fstrm = regexprep(fstrm,'(% line types:.+?)/.+?%',['$1',sprintf('%s\r',new_style{:}),'%']);
    138146
    139147% Write the output file
  • issm/trunk-jpl/externalpackages/export_fig/ghostscript.m

    r19993 r21315  
     1function varargout = ghostscript(cmd)
    12%GHOSTSCRIPT  Calls a local GhostScript executable with the input command
    23%
     
    2021%   result - Output from ghostscript.
    2122
    22 % Copyright: Oliver Woodford, 2009-2013
     23% Copyright: Oliver Woodford, 2009-2015, Yair Altman 2015-
     24%{
     25% Thanks to Jonas Dorn for the fix for the title of the uigetdir window on Mac OS.
     26% Thanks to Nathan Childress for the fix to default location on 64-bit Windows systems.
     27% 27/04/11 - Find 64-bit Ghostscript on Windows. Thanks to Paul Durack and
     28%            Shaun Kline for pointing out the issue
     29% 04/05/11 - Thanks to David Chorlian for pointing out an alternative
     30%            location for gs on linux.
     31% 12/12/12 - Add extra executable name on Windows. Thanks to Ratish
     32%            Punnoose for highlighting the issue.
     33% 28/06/13 - Fix error using GS 9.07 in Linux. Many thanks to Jannick
     34%            Steinbring for proposing the fix.
     35% 24/10/13 - Fix error using GS 9.07 in Linux. Many thanks to Johannes
     36%            for the fix.
     37% 23/01/14 - Add full path to ghostscript.txt in warning. Thanks to Koen
     38%            Vermeer for raising the issue.
     39% 27/02/15 - If Ghostscript croaks, display suggested workarounds
     40% 30/03/15 - Improved performance by caching status of GS path check, if ok
     41% 14/05/15 - Clarified warning message in case GS path could not be saved
     42% 29/05/15 - Avoid cryptic error in case the ghostscipt path cannot be saved (issue #74)
     43% 10/11/15 - Custom GS installation webpage for MacOS. Thanks to Andy Hueni via FEX
     44%}
    2345
    24 % Thanks to Jonas Dorn for the fix for the title of the uigetdir window on
    25 % Mac OS.
    26 % Thanks to Nathan Childress for the fix to the default location on 64-bit
    27 % Windows systems.
    28 % 27/4/11 - Find 64-bit Ghostscript on Windows. Thanks to Paul Durack and
    29 % Shaun Kline for pointing out the issue
    30 % 4/5/11 - Thanks to David Chorlian for pointing out an alternative
    31 % location for gs on linux.
    32 % 12/12/12 - Add extra executable name on Windows. Thanks to Ratish
    33 % Punnoose for highlighting the issue.
    34 % 28/6/13 - Fix error using GS 9.07 in Linux. Many thanks to Jannick
    35 % Steinbring for proposing the fix.
    36 % 24/10/13 - Fix error using GS 9.07 in Linux. Many thanks to Johannes
    37 % for the fix.
    38 % 23/01/2014 - Add full path to ghostscript.txt in warning. Thanks to Koen
    39 % Vermeer for raising the issue.
    40 
    41 function varargout = ghostscript(cmd)
    42 % Initialize any required system calls before calling ghostscript
    43 shell_cmd = '';
    44 if isunix
    45     shell_cmd = 'export LD_LIBRARY_PATH=""; '; % Avoids an error on Linux with GS 9.07
    46 end
    47 if ismac
    48     shell_cmd = 'export DYLD_LIBRARY_PATH=""; ';  % Avoids an error on Mac with GS 9.07
    49 end
    50 % Call ghostscript
    51 [varargout{1:nargout}] = system(sprintf('%s"%s" %s', shell_cmd, gs_path, cmd));
     46    try
     47        % Call ghostscript
     48        [varargout{1:nargout}] = system([gs_command(gs_path()) cmd]);
     49    catch err
     50        % Display possible workarounds for Ghostscript croaks
     51        url1 = 'https://github.com/altmany/export_fig/issues/12#issuecomment-61467998';  % issue #12
     52        url2 = 'https://github.com/altmany/export_fig/issues/20#issuecomment-63826270';  % issue #20
     53        hg2_str = ''; if using_hg2, hg2_str = ' or Matlab R2014a'; end
     54        fprintf(2, 'Ghostscript error. Rolling back to GS 9.10%s may possibly solve this:\n * <a href="%s">%s</a> ',hg2_str,url1,url1);
     55        if using_hg2
     56            fprintf(2, '(GS 9.10)\n * <a href="%s">%s</a> (R2014a)',url2,url2);
     57        end
     58        fprintf('\n\n');
     59        if ismac || isunix
     60            url3 = 'https://github.com/altmany/export_fig/issues/27';  % issue #27
     61            fprintf(2, 'Alternatively, this may possibly be due to a font path issue:\n * <a href="%s">%s</a>\n\n',url3,url3);
     62            % issue #20
     63            fpath = which(mfilename);
     64            if isempty(fpath), fpath = [mfilename('fullpath') '.m']; end
     65            fprintf(2, 'Alternatively, if you are using csh, modify shell_cmd from "export..." to "setenv ..."\nat the bottom of <a href="matlab:opentoline(''%s'',174)">%s</a>\n\n',fpath,fpath);
     66        end
     67        rethrow(err);
     68    end
    5269end
    5370
    5471function path_ = gs_path
    55 % Return a valid path
    56 % Start with the currently set path
    57 path_ = user_string('ghostscript');
    58 % Check the path works
    59 if check_gs_path(path_)
    60     return
    61 end
    62 % Check whether the binary is on the path
    63 if ispc
    64     bin = {'gswin32c.exe', 'gswin64c.exe', 'gs'};
    65 else
    66     bin = {'gs'};
    67 end
    68 for a = 1:numel(bin)
    69     path_ = bin{a};
    70     if check_store_gs_path(path_)
     72    % Return a valid path
     73    % Start with the currently set path
     74    path_ = user_string('ghostscript');
     75    % Check the path works
     76    if check_gs_path(path_)
    7177        return
    7278    end
    73 end
    74 % Search the obvious places
    75 if ispc
    76     default_location = 'C:\Program Files\gs\';
    77     dir_list = dir(default_location);
    78     if isempty(dir_list)
    79         default_location = 'C:\Program Files (x86)\gs\'; % Possible location on 64-bit systems
     79    % Check whether the binary is on the path
     80    if ispc
     81        bin = {'gswin32c.exe', 'gswin64c.exe', 'gs'};
     82    else
     83        bin = {'gs'};
     84    end
     85    for a = 1:numel(bin)
     86        path_ = bin{a};
     87        if check_store_gs_path(path_)
     88            return
     89        end
     90    end
     91    % Search the obvious places
     92    if ispc
     93        default_location = 'C:\Program Files\gs\';
    8094        dir_list = dir(default_location);
     95        if isempty(dir_list)
     96            default_location = 'C:\Program Files (x86)\gs\'; % Possible location on 64-bit systems
     97            dir_list = dir(default_location);
     98        end
     99        executable = {'\bin\gswin32c.exe', '\bin\gswin64c.exe'};
     100        ver_num = 0;
     101        % If there are multiple versions, use the newest
     102        for a = 1:numel(dir_list)
     103            ver_num2 = sscanf(dir_list(a).name, 'gs%g');
     104            if ~isempty(ver_num2) && ver_num2 > ver_num
     105                for b = 1:numel(executable)
     106                    path2 = [default_location dir_list(a).name executable{b}];
     107                    if exist(path2, 'file') == 2
     108                        path_ = path2;
     109                        ver_num = ver_num2;
     110                    end
     111                end
     112            end
     113        end
     114        if check_store_gs_path(path_)
     115            return
     116        end
     117    else
     118        executable = {'/usr/bin/gs', '/usr/local/bin/gs'};
     119        for a = 1:numel(executable)
     120            path_ = executable{a};
     121            if check_store_gs_path(path_)
     122                return
     123            end
     124        end
    81125    end
    82     executable = {'\bin\gswin32c.exe', '\bin\gswin64c.exe'};
    83     ver_num = 0;
    84     % If there are multiple versions, use the newest
    85     for a = 1:numel(dir_list)
    86         ver_num2 = sscanf(dir_list(a).name, 'gs%g');
    87         if ~isempty(ver_num2) && ver_num2 > ver_num
    88             for b = 1:numel(executable)
    89                 path2 = [default_location dir_list(a).name executable{b}];
    90                 if exist(path2, 'file') == 2
    91                     path_ = path2;
    92                     ver_num = ver_num2;
     126    % Ask the user to enter the path
     127    while true
     128        if strncmp(computer, 'MAC', 3) % Is a Mac
     129            % Give separate warning as the uigetdir dialogue box doesn't have a
     130            % title
     131            uiwait(warndlg('Ghostscript not found. Please locate the program.'))
     132        end
     133        base = uigetdir('/', 'Ghostcript not found. Please locate the program.');
     134        if isequal(base, 0)
     135            % User hit cancel or closed window
     136            break;
     137        end
     138        base = [base filesep]; %#ok<AGROW>
     139        bin_dir = {'', ['bin' filesep], ['lib' filesep]};
     140        for a = 1:numel(bin_dir)
     141            for b = 1:numel(bin)
     142                path_ = [base bin_dir{a} bin{b}];
     143                if exist(path_, 'file') == 2
     144                    if check_store_gs_path(path_)
     145                        return
     146                    end
    93147                end
    94148            end
    95149        end
    96150    end
    97     if check_store_gs_path(path_)
    98         return
     151    if ismac
     152        error('Ghostscript not found. Have you installed it (http://pages.uoregon.edu/koch)?');
     153    else
     154        error('Ghostscript not found. Have you installed it from www.ghostscript.com?');
    99155    end
    100 else
    101     executable = {'/usr/bin/gs', '/usr/local/bin/gs'};
    102     for a = 1:numel(executable)
    103         path_ = executable{a};
    104         if check_store_gs_path(path_)
    105             return
    106         end
    107     end
    108 end
    109 % Ask the user to enter the path
    110 while 1
    111     if strncmp(computer, 'MAC', 3) % Is a Mac
    112         % Give separate warning as the uigetdir dialogue box doesn't have a
    113         % title
    114         uiwait(warndlg('Ghostscript not found. Please locate the program.'))
    115     end
    116     base = uigetdir('/', 'Ghostcript not found. Please locate the program.');
    117     if isequal(base, 0)
    118         % User hit cancel or closed window
    119         break;
    120     end
    121     base = [base filesep];
    122     bin_dir = {'', ['bin' filesep], ['lib' filesep]};
    123     for a = 1:numel(bin_dir)
    124         for b = 1:numel(bin)
    125             path_ = [base bin_dir{a} bin{b}];
    126             if exist(path_, 'file') == 2
    127                 if check_store_gs_path(path_)
    128                     return
    129                 end
    130             end
    131         end
    132     end
    133 end
    134 error('Ghostscript not found. Have you installed it from www.ghostscript.com?');
    135156end
    136157
    137158function good = check_store_gs_path(path_)
    138 % Check the path is valid
    139 good = check_gs_path(path_);
    140 if ~good
    141     return
    142 end
    143 % Update the current default path to the path found
    144 if ~user_string('ghostscript', path_)
    145     warning('Path to ghostscript installation could not be saved. Enter it manually in %s.', fullfile(fileparts(which('user_string.m')), '.ignore', 'ghostscript.txt'));
    146     return
    147 end
     159    % Check the path is valid
     160    good = check_gs_path(path_);
     161    if ~good
     162        return
     163    end
     164    % Update the current default path to the path found
     165    if ~user_string('ghostscript', path_)
     166        filename = fullfile(fileparts(which('user_string.m')), '.ignore', 'ghostscript.txt');
     167        warning('Path to ghostscript installation could not be saved in %s (perhaps a permissions issue). You can manually create this file and set its contents to %s, to improve performance in future invocations (this warning is safe to ignore).', filename, path_);
     168        return
     169    end
    148170end
    149171
    150172function good = check_gs_path(path_)
    151 % Check the path is valid
    152 shell_cmd = '';
    153 if ismac
    154     shell_cmd = 'export DYLD_LIBRARY_PATH=""; ';  % Avoids an error on Mac with GS 9.07
     173    persistent isOk
     174    if isempty(path_)
     175        isOk = false;
     176    elseif ~isequal(isOk,true)
     177        % Check whether the path is valid
     178        [status, message] = system([gs_command(path_) '-h']); %#ok<ASGLU>
     179        isOk = status == 0;
     180    end
     181    good = isOk;
    155182end
    156 [good, message] = system(sprintf('%s"%s" -h', shell_cmd, path_));
    157 good = good == 0;
     183
     184function cmd = gs_command(path_)
     185    % Initialize any required system calls before calling ghostscript
     186    % TODO: in Unix/Mac, find a way to determine whether to use "export" (bash) or "setenv" (csh/tcsh)
     187    shell_cmd = '';
     188    if isunix
     189        shell_cmd = 'export LD_LIBRARY_PATH=""; '; % Avoids an error on Linux with GS 9.07
     190    end
     191    if ismac
     192        shell_cmd = 'export DYLD_LIBRARY_PATH=""; ';  % Avoids an error on Mac with GS 9.07
     193    end
     194    % Construct the command string
     195    cmd = sprintf('%s"%s" ', shell_cmd, path_);
    158196end
  • issm/trunk-jpl/externalpackages/export_fig/isolate_axes.m

    r19993 r21315  
     1function fh = isolate_axes(ah, vis)
    12%ISOLATE_AXES Isolate the specified axes in a figure on their own
    23%
     
    2223
    2324% Thank you to Rosella Blatt for reporting a bug to do with axes in GUIs
    24 % 16/3/2012 Moved copyfig to its own function. Thanks to Bob Fratantonio
    25 % for pointing out that the function is also used in export_fig.m.
    26 % 12/12/12 - Add support for isolating uipanels. Thanks to michael for
    27 % suggesting it.
    28 % 08/10/13 - Bug fix to allchildren suggested by Will Grant (many thanks!).
    29 % 05/12/13 - Bug fix to axes having different units. Thanks to Remington
    30 % Reid for reporting the issue.
     25% 16/03/12: Moved copyfig to its own function. Thanks to Bob Fratantonio
     26%           for pointing out that the function is also used in export_fig.m
     27% 12/12/12: Add support for isolating uipanels. Thanks to michael for suggesting it
     28% 08/10/13: Bug fix to allchildren suggested by Will Grant (many thanks!)
     29% 05/12/13: Bug fix to axes having different units. Thanks to Remington Reid for reporting
     30% 21/04/15: Bug fix for exporting uipanels with legend/colorbar on HG1 (reported by Alvaro
     31%           on FEX page as a comment on 24-Apr-2014); standardized indentation & help section
     32% 22/04/15: Bug fix: legends and colorbars were not exported when exporting axes handle in HG2
    3133
    32 function fh = isolate_axes(ah, vis)
    33 % Make sure we have an array of handles
    34 if ~all(ishandle(ah))
    35     error('ah must be an array of handles');
    36 end
    37 % Check that the handles are all for axes or uipanels, and are all in the same figure
    38 fh = ancestor(ah(1), 'figure');
    39 nAx = numel(ah);
    40 for a = 1:nAx
    41     if ~ismember(get(ah(a), 'Type'), {'axes', 'uipanel'})
    42         error('All handles must be axes or uipanel handles.');
     34    % Make sure we have an array of handles
     35    if ~all(ishandle(ah))
     36        error('ah must be an array of handles');
    4337    end
    44     if ~isequal(ancestor(ah(a), 'figure'), fh)
    45         error('Axes must all come from the same figure.');
     38    % Check that the handles are all for axes or uipanels, and are all in the same figure
     39    fh = ancestor(ah(1), 'figure');
     40    nAx = numel(ah);
     41    for a = 1:nAx
     42        if ~ismember(get(ah(a), 'Type'), {'axes', 'uipanel'})
     43            error('All handles must be axes or uipanel handles.');
     44        end
     45        if ~isequal(ancestor(ah(a), 'figure'), fh)
     46            error('Axes must all come from the same figure.');
     47        end
    4648    end
    47 end
    48 % Tag the objects so we can find them in the copy
    49 old_tag = get(ah, 'Tag');
    50 if nAx == 1
    51     old_tag = {old_tag};
    52 end
    53 set(ah, 'Tag', 'ObjectToCopy');
    54 % Create a new figure exactly the same as the old one
    55 fh = copyfig(fh); %copyobj(fh, 0);
    56 if nargin < 2 || ~vis
    57     set(fh, 'Visible', 'off');
    58 end
    59 % Reset the object tags
    60 for a = 1:nAx
    61     set(ah(a), 'Tag', old_tag{a});
    62 end
    63 % Find the objects to save
    64 ah = findall(fh, 'Tag', 'ObjectToCopy');
    65 if numel(ah) ~= nAx
    66     close(fh);
    67     error('Incorrect number of objects found.');
    68 end
    69 % Set the axes tags to what they should be
    70 for a = 1:nAx
    71     set(ah(a), 'Tag', old_tag{a});
    72 end
    73 % Keep any legends and colorbars which overlap the subplots
    74 lh = findall(fh, 'Type', 'axes', '-and', {'Tag', 'legend', '-or', 'Tag', 'Colorbar'});
    75 nLeg = numel(lh);
    76 if nLeg > 0
    77     set([ah(:); lh(:)], 'Units', 'normalized');
    78     ax_pos = get(ah, 'OuterPosition');
    79     if nAx > 1
    80         ax_pos = cell2mat(ax_pos(:));
     49    % Tag the objects so we can find them in the copy
     50    old_tag = get(ah, 'Tag');
     51    if nAx == 1
     52        old_tag = {old_tag};
    8153    end
    82     ax_pos(:,3:4) = ax_pos(:,3:4) + ax_pos(:,1:2);
    83     leg_pos = get(lh, 'OuterPosition');
    84     if nLeg > 1;
    85         leg_pos = cell2mat(leg_pos);
     54    set(ah, 'Tag', 'ObjectToCopy');
     55    % Create a new figure exactly the same as the old one
     56    fh = copyfig(fh); %copyobj(fh, 0);
     57    if nargin < 2 || ~vis
     58        set(fh, 'Visible', 'off');
    8659    end
    87     leg_pos(:,3:4) = leg_pos(:,3:4) + leg_pos(:,1:2);
    88     ax_pos = shiftdim(ax_pos, -1);
    89     % Overlap test
    90     M = bsxfun(@lt, leg_pos(:,1), ax_pos(:,:,3)) & ...
    91         bsxfun(@lt, leg_pos(:,2), ax_pos(:,:,4)) & ...
    92         bsxfun(@gt, leg_pos(:,3), ax_pos(:,:,1)) & ...
    93         bsxfun(@gt, leg_pos(:,4), ax_pos(:,:,2));
    94     ah = [ah; lh(any(M, 2))];
    95 end
    96 % Get all the objects in the figure
    97 axs = findall(fh);
    98 % Delete everything except for the input objects and associated items
    99 delete(axs(~ismember(axs, [ah; allchildren(ah); allancestors(ah)])));
     60    % Reset the object tags
     61    for a = 1:nAx
     62        set(ah(a), 'Tag', old_tag{a});
     63    end
     64    % Find the objects to save
     65    ah = findall(fh, 'Tag', 'ObjectToCopy');
     66    if numel(ah) ~= nAx
     67        close(fh);
     68        error('Incorrect number of objects found.');
     69    end
     70    % Set the axes tags to what they should be
     71    for a = 1:nAx
     72        set(ah(a), 'Tag', old_tag{a});
     73    end
     74    % Keep any legends and colorbars which overlap the subplots
     75    % Note: in HG1 these are axes objects; in HG2 they are separate objects, therefore we
     76    %       don't test for the type, only the tag (hopefully nobody but Matlab uses them!)
     77    lh = findall(fh, 'Tag', 'legend', '-or', 'Tag', 'Colorbar');
     78    nLeg = numel(lh);
     79    if nLeg > 0
     80        set([ah(:); lh(:)], 'Units', 'normalized');
     81        try
     82            ax_pos = get(ah, 'OuterPosition'); % axes and figures have the OuterPosition property
     83        catch
     84            ax_pos = get(ah, 'Position'); % uipanels only have Position, not OuterPosition
     85        end
     86        if nAx > 1
     87            ax_pos = cell2mat(ax_pos(:));
     88        end
     89        ax_pos(:,3:4) = ax_pos(:,3:4) + ax_pos(:,1:2);
     90        try
     91            leg_pos = get(lh, 'OuterPosition');
     92        catch
     93            leg_pos = get(lh, 'Position');  % No OuterPosition in HG2, only in HG1
     94        end
     95        if nLeg > 1;
     96            leg_pos = cell2mat(leg_pos);
     97        end
     98        leg_pos(:,3:4) = leg_pos(:,3:4) + leg_pos(:,1:2);
     99        ax_pos = shiftdim(ax_pos, -1);
     100        % Overlap test
     101        M = bsxfun(@lt, leg_pos(:,1), ax_pos(:,:,3)) & ...
     102            bsxfun(@lt, leg_pos(:,2), ax_pos(:,:,4)) & ...
     103            bsxfun(@gt, leg_pos(:,3), ax_pos(:,:,1)) & ...
     104            bsxfun(@gt, leg_pos(:,4), ax_pos(:,:,2));
     105        ah = [ah; lh(any(M, 2))];
     106    end
     107    % Get all the objects in the figure
     108    axs = findall(fh);
     109    % Delete everything except for the input objects and associated items
     110    delete(axs(~ismember(axs, [ah; allchildren(ah); allancestors(ah)])));
    100111end
    101112
    102113function ah = allchildren(ah)
    103 ah = findall(ah);
    104 if iscell(ah)
    105     ah = cell2mat(ah);
    106 end
    107 ah = ah(:);
     114    ah = findall(ah);
     115    if iscell(ah)
     116        ah = cell2mat(ah);
     117    end
     118    ah = ah(:);
    108119end
    109120
    110121function ph = allancestors(ah)
    111 ph = [];
    112 for a = 1:numel(ah)
    113     h = get(ah(a), 'parent');
    114     while h ~= 0
    115         ph = [ph; h];
    116         h = get(h, 'parent');
     122    ph = [];
     123    for a = 1:numel(ah)
     124        h = get(ah(a), 'parent');
     125        while h ~= 0
     126            ph = [ph; h];
     127            h = get(h, 'parent');
     128        end
    117129    end
    118130end
    119 end
  • issm/trunk-jpl/externalpackages/export_fig/pdftops.m

    r19993 r21315  
    1616%
    1717% IN:
    18 %   cmd - Command string to be passed into pdftops.
     18%   cmd - Command string to be passed into pdftops (e.g. '-help').
    1919%
    2020% OUT:
     
    2424% Copyright: Oliver Woodford, 2009-2010
    2525
    26 % Thanks to Jonas Dorn for the fix for the title of the uigetdir window on
    27 % Mac OS.
    28 % Thanks to Christoph Hertel for pointing out a bug in check_xpdf_path
    29 % under linux.
     26% Thanks to Jonas Dorn for the fix for the title of the uigetdir window on Mac OS.
     27% Thanks to Christoph Hertel for pointing out a bug in check_xpdf_path under linux.
    3028% 23/01/2014 - Add full path to pdftops.txt in warning.
     29% 27/05/2015 - Fixed alert in case of missing pdftops; fixed code indentation
     30% 02/05/2016 - Added possible error explanation suggested by Michael Pacer (issue #137)
     31% 02/05/2016 - Search additional possible paths suggested by Jonas Stein (issue #147)
     32% 03/05/2016 - Display the specific error message if pdftops fails for some reason (issue #148)
    3133
    32 % Call pdftops
    33 [varargout{1:nargout}] = system(sprintf('"%s" %s', xpdf_path, cmd));
     34    % Call pdftops
     35    [varargout{1:nargout}] = system(sprintf('"%s" %s', xpdf_path, cmd));
    3436end
    3537
    3638function path_ = xpdf_path
    37 % Return a valid path
    38 % Start with the currently set path
    39 path_ = user_string('pdftops');
    40 % Check the path works
    41 if check_xpdf_path(path_)
    42     return
    43 end
    44 % Check whether the binary is on the path
    45 if ispc
    46     bin = 'pdftops.exe';
    47 else
    48     bin = 'pdftops';
    49 end
    50 if check_store_xpdf_path(bin)
    51     path_ = bin;
    52     return
    53 end
    54 % Search the obvious places
    55 if ispc
    56     path_ = 'C:\Program Files\xpdf\pdftops.exe';
    57 else
    58     path_ = '/usr/local/bin/pdftops';
    59 end
    60 if check_store_xpdf_path(path_)
    61     return
    62 end
    63 % Ask the user to enter the path
    64 while 1
    65     if strncmp(computer,'MAC',3) % Is a Mac
    66         % Give separate warning as the uigetdir dialogue box doesn't have a
    67         % title
    68         uiwait(warndlg('Pdftops not found. Please locate the program, or install xpdf-tools from http://users.phg-online.de/tk/MOSXS/.'))
     39    % Return a valid path
     40    % Start with the currently set path
     41    path_ = user_string('pdftops');
     42    % Check the path works
     43    if check_xpdf_path(path_)
     44        return
    6945    end
    70     base = uigetdir('/', 'Pdftops not found. Please locate the program.');
    71     if isequal(base, 0)
    72         % User hit cancel or closed window
    73         break;
     46    % Check whether the binary is on the path
     47    if ispc
     48        bin = 'pdftops.exe';
     49    else
     50        bin = 'pdftops';
    7451    end
    75     base = [base filesep];
    76     bin_dir = {'', ['bin' filesep], ['lib' filesep]};
    77     for a = 1:numel(bin_dir)
    78         path_ = [base bin_dir{a} bin];
    79         if exist(path_, 'file') == 2
    80             break;
     52    if check_store_xpdf_path(bin)
     53        path_ = bin;
     54        return
     55    end
     56    % Search the obvious places
     57    if ispc
     58        paths = {'C:\Program Files\xpdf\pdftops.exe', 'C:\Program Files (x86)\xpdf\pdftops.exe'};
     59    else
     60        paths = {'/usr/bin/pdftops', '/usr/local/bin/pdftops'};
     61    end
     62    for a = 1:numel(paths)
     63        path_ = paths{a};
     64        if check_store_xpdf_path(path_)
     65            return
    8166        end
    8267    end
    83     if check_store_xpdf_path(path_)
     68
     69    % Ask the user to enter the path
     70    errMsg1 = 'Pdftops not found. Please locate the program, or install xpdf-tools from ';
     71    url1 = 'http://foolabs.com/xpdf';
     72    fprintf(2, '%s\n', [errMsg1 '<a href="matlab:web(''-browser'',''' url1 ''');">' url1 '</a>']);
     73    errMsg1 = [errMsg1 url1];
     74    %if strncmp(computer,'MAC',3) % Is a Mac
     75    %    % Give separate warning as the MacOS uigetdir dialogue box doesn't have a title
     76    %    uiwait(warndlg(errMsg1))
     77    %end
     78
     79    % Provide an alternative possible explanation as per issue #137
     80    errMsg2 = 'If you have pdftops installed, perhaps Matlab is shaddowing it as described in ';
     81    url2 = 'https://github.com/altmany/export_fig/issues/137';
     82    fprintf(2, '%s\n', [errMsg2 '<a href="matlab:web(''-browser'',''' url2 ''');">issue #137</a>']);
     83    errMsg2 = [errMsg2 url1];
     84
     85    state = 0;
     86    while 1
     87        if state
     88            option1 = 'Install pdftops';
     89        else
     90            option1 = 'Issue #137';
     91        end
     92        answer = questdlg({errMsg1,'',errMsg2},'Pdftops error',option1,'Locate pdftops','Cancel','Cancel');
     93        drawnow;  % prevent a Matlab hang: http://undocumentedmatlab.com/blog/solving-a-matlab-hang-problem
     94        switch answer
     95            case 'Install pdftops'
     96                web('-browser',url1);
     97            case 'Issue #137'
     98                web('-browser',url2);
     99                state = 1;
     100            case 'Locate pdftops'
     101                base = uigetdir('/', errMsg1);
     102                if isequal(base, 0)
     103                    % User hit cancel or closed window
     104                    break
     105                end
     106                base = [base filesep]; %#ok<AGROW>
     107                bin_dir = {'', ['bin' filesep], ['lib' filesep]};
     108                for a = 1:numel(bin_dir)
     109                    path_ = [base bin_dir{a} bin];
     110                    if exist(path_, 'file') == 2
     111                        break
     112                    end
     113                end
     114                if check_store_xpdf_path(path_)
     115                    return
     116                end
     117
     118            otherwise  % User hit Cancel or closed window
     119                break
     120        end
     121    end
     122    error('pdftops executable not found.');
     123end
     124
     125function good = check_store_xpdf_path(path_)
     126    % Check the path is valid
     127    good = check_xpdf_path(path_);
     128    if ~good
     129        return
     130    end
     131    % Update the current default path to the path found
     132    if ~user_string('pdftops', path_)
     133        warning('Path to pdftops executable could not be saved. Enter it manually in %s.', fullfile(fileparts(which('user_string.m')), '.ignore', 'pdftops.txt'));
    84134        return
    85135    end
    86136end
    87 error('pdftops executable not found.');
    88 end
    89 
    90 function good = check_store_xpdf_path(path_)
    91 % Check the path is valid
    92 good = check_xpdf_path(path_);
    93 if ~good
    94     return
    95 end
    96 % Update the current default path to the path found
    97 if ~user_string('pdftops', path_)
    98     warning('Path to pdftops executable could not be saved. Enter it manually in %s.', fullfile(fileparts(which('user_string.m')), '.ignore', 'pdftops.txt'));
    99     return
    100 end
    101 end
    102137
    103138function good = check_xpdf_path(path_)
    104 % Check the path is valid
    105 [good, message] = system(sprintf('"%s" -h', path_));
    106 % system returns good = 1 even when the command runs
    107 % Look for something distinct in the help text
    108 good = ~isempty(strfind(message, 'PostScript'));
     139    % Check the path is valid
     140    [good, message] = system(sprintf('"%s" -h', path_)); %#ok<ASGLU>
     141    % system returns good = 1 even when the command runs
     142    % Look for something distinct in the help text
     143    good = ~isempty(strfind(message, 'PostScript'));
     144
     145    % Display the error message if the pdftops executable exists but fails for some reason
     146    if ~good && exist(path_,'file')  % file exists but generates an error
     147        fprintf('Error running %s:\n', path_);
     148        fprintf(2,'%s\n\n',message);
     149    end
    109150end
  • issm/trunk-jpl/externalpackages/export_fig/print2array.m

    r19993 r21315  
     1function [A, bcol] = print2array(fig, res, renderer, gs_options)
    12%PRINT2ARRAY  Exports a figure to an image array
    23%
     
    67%   A = print2array(figure_handle, resolution)
    78%   A = print2array(figure_handle, resolution, renderer)
     9%   A = print2array(figure_handle, resolution, renderer, gs_options)
    810%   [A bcol] = print2array(...)
    911%
     
    2022%   renderer - string containing the renderer paramater to be passed to
    2123%              print. Default: '-opengl'.
     24%   gs_options - optional ghostscript options (e.g.: '-dNoOutputFonts'). If
     25%                multiple options are needed, enclose in call array: {'-a','-b'}
    2226%
    2327% OUT:
     
    2529%   bcol - 1x3 uint8 vector of the background color
    2630
    27 % Copyright (C) Oliver Woodford 2008-2012
    28 
     31% Copyright (C) Oliver Woodford 2008-2014, Yair Altman 2015-
     32%{
    2933% 05/09/11: Set EraseModes to normal when using opengl or zbuffer
    30 %           renderers. Thanks to Pawel Kocieniewski for reporting the
    31 %           issue.
    32 % 21/09/11: Bug fix: unit8 -> uint8! Thanks to Tobias Lamour for reporting
    33 %           the issue.
    34 % 14/11/11: Bug fix: stop using hardcopy(), as it interfered with figure
    35 %           size and erasemode settings. Makes it a bit slower, but more
    36 %           reliable. Thanks to Phil Trinh and Meelis Lootus for reporting
    37 %           the issues.
     34%           renderers. Thanks to Pawel Kocieniewski for reporting the issue.
     35% 21/09/11: Bug fix: unit8 -> uint8! Thanks to Tobias Lamour for reporting it.
     36% 14/11/11: Bug fix: stop using hardcopy(), as it interfered with figure size
     37%           and erasemode settings. Makes it a bit slower, but more reliable.
     38%           Thanks to Phil Trinh and Meelis Lootus for reporting the issues.
    3839% 09/12/11: Pass font path to ghostscript.
    3940% 27/01/12: Bug fix affecting painters rendering tall figures. Thanks to
    4041%           Ken Campbell for reporting it.
    41 % 03/04/12: Bug fix to median input. Thanks to Andy Matthews for reporting
    42 %           it.
     42% 03/04/12: Bug fix to median input. Thanks to Andy Matthews for reporting it.
    4343% 26/10/12: Set PaperOrientation to portrait. Thanks to Michael Watts for
    4444%           reporting the issue.
     45% 26/02/15: If temp dir is not writable, use the current folder for temp
     46%           EPS/TIF files (Javier Paredes)
     47% 27/02/15: Display suggested workarounds to internal print() error (issue #16)
     48% 28/02/15: Enable users to specify optional ghostscript options (issue #36)
     49% 10/03/15: Fixed minor warning reported by Paul Soderlind; fixed code indentation
     50% 28/05/15: Fixed issue #69: patches with LineWidth==0.75 appear wide (internal bug in Matlab's print() func)
     51% 07/07/15: Fixed issue #83: use numeric handles in HG1
     52%}
    4553
    46 function [A, bcol] = print2array(fig, res, renderer)
    47 % Generate default input arguments, if needed
    48 if nargin < 2
    49     res = 1;
    50     if nargin < 1
    51         fig = gcf;
    52     end
    53 end
    54 % Warn if output is large
    55 old_mode = get(fig, 'Units');
    56 set(fig, 'Units', 'pixels');
    57 px = get(fig, 'Position');
    58 set(fig, 'Units', old_mode);
    59 npx = prod(px(3:4)*res)/1e6;
    60 if npx > 30
    61     % 30M pixels or larger!
    62     warning('MATLAB:LargeImage', 'print2array generating a %.1fM pixel image. This could be slow and might also cause memory problems.', npx);
    63 end
    64 % Retrieve the background colour
    65 bcol = get(fig, 'Color');
    66 % Set the resolution parameter
    67 res_str = ['-r' num2str(ceil(get(0, 'ScreenPixelsPerInch')*res))];
    68 % Generate temporary file name
    69 tmp_nam = [tempname '.tif'];
    70 if nargin > 2 && strcmp(renderer, '-painters')
    71     % Print to eps file
    72     tmp_eps = [tempname '.eps'];
    73     print2eps(tmp_eps, fig, 0, renderer, '-loose');
     54    % Generate default input arguments, if needed
     55    if nargin < 2
     56        res = 1;
     57        if nargin < 1
     58            fig = gcf;
     59        end
     60    end
     61    % Warn if output is large
     62    old_mode = get(fig, 'Units');
     63    set(fig, 'Units', 'pixels');
     64    px = get(fig, 'Position');
     65    set(fig, 'Units', old_mode);
     66    npx = prod(px(3:4)*res)/1e6;
     67    if npx > 30
     68        % 30M pixels or larger!
     69        warning('MATLAB:LargeImage', 'print2array generating a %.1fM pixel image. This could be slow and might also cause memory problems.', npx);
     70    end
     71    % Retrieve the background colour
     72    bcol = get(fig, 'Color');
     73    % Set the resolution parameter
     74    res_str = ['-r' num2str(ceil(get(0, 'ScreenPixelsPerInch')*res))];
     75    % Generate temporary file name
     76    tmp_nam = [tempname '.tif'];
    7477    try
    75         % Initialize the command to export to tiff using ghostscript
    76         cmd_str = ['-dEPSCrop -q -dNOPAUSE -dBATCH ' res_str ' -sDEVICE=tiff24nc'];
    77         % Set the font path
    78         fp = font_path();
    79         if ~isempty(fp)
    80             cmd_str = [cmd_str ' -sFONTPATH="' fp '"'];
    81         end
    82         % Add the filenames
    83         cmd_str = [cmd_str ' -sOutputFile="' tmp_nam '" "' tmp_eps '"'];
    84         % Execute the ghostscript command
    85         ghostscript(cmd_str);
    86     catch me
     78        % Ensure that the temp dir is writable (Javier Paredes 26/2/15)
     79        fid = fopen(tmp_nam,'w');
     80        fwrite(fid,1);
     81        fclose(fid);
     82        delete(tmp_nam);  % cleanup
     83        isTempDirOk = true;
     84    catch
     85        % Temp dir is not writable, so use the current folder
     86        [dummy,fname,fext] = fileparts(tmp_nam); %#ok<ASGLU>
     87        fpath = pwd;
     88        tmp_nam = fullfile(fpath,[fname fext]);
     89        isTempDirOk = false;
     90    end
     91    % Enable users to specify optional ghostscript options (issue #36)
     92    if nargin > 3 && ~isempty(gs_options)
     93        if iscell(gs_options)
     94            gs_options = sprintf(' %s',gs_options{:});
     95        elseif ~ischar(gs_options)
     96            error('gs_options input argument must be a string or cell-array of strings');
     97        else
     98            gs_options = [' ' gs_options];
     99        end
     100    else
     101        gs_options = '';
     102    end
     103    if nargin > 2 && strcmp(renderer, '-painters')
     104        % Print to eps file
     105        if isTempDirOk
     106            tmp_eps = [tempname '.eps'];
     107        else
     108            tmp_eps = fullfile(fpath,[fname '.eps']);
     109        end
     110        print2eps(tmp_eps, fig, 0, renderer, '-loose');
     111        try
     112            % Initialize the command to export to tiff using ghostscript
     113            cmd_str = ['-dEPSCrop -q -dNOPAUSE -dBATCH ' res_str ' -sDEVICE=tiff24nc'];
     114            % Set the font path
     115            fp = font_path();
     116            if ~isempty(fp)
     117                cmd_str = [cmd_str ' -sFONTPATH="' fp '"'];
     118            end
     119            % Add the filenames
     120            cmd_str = [cmd_str ' -sOutputFile="' tmp_nam '" "' tmp_eps '"' gs_options];
     121            % Execute the ghostscript command
     122            ghostscript(cmd_str);
     123        catch me
     124            % Delete the intermediate file
     125            delete(tmp_eps);
     126            rethrow(me);
     127        end
    87128        % Delete the intermediate file
    88129        delete(tmp_eps);
    89         rethrow(me);
    90     end
    91     % Delete the intermediate file
    92     delete(tmp_eps);
    93     % Read in the generated bitmap
    94     A = imread(tmp_nam);
    95     % Delete the temporary bitmap file
    96     delete(tmp_nam);
    97     % Set border pixels to the correct colour
    98     if isequal(bcol, 'none')
    99         bcol = [];
    100     elseif isequal(bcol, [1 1 1])
    101         bcol = uint8([255 255 255]);
     130        % Read in the generated bitmap
     131        A = imread(tmp_nam);
     132        % Delete the temporary bitmap file
     133        delete(tmp_nam);
     134        % Set border pixels to the correct colour
     135        if isequal(bcol, 'none')
     136            bcol = [];
     137        elseif isequal(bcol, [1 1 1])
     138            bcol = uint8([255 255 255]);
     139        else
     140            for l = 1:size(A, 2)
     141                if ~all(reshape(A(:,l,:) == 255, [], 1))
     142                    break;
     143                end
     144            end
     145            for r = size(A, 2):-1:l
     146                if ~all(reshape(A(:,r,:) == 255, [], 1))
     147                    break;
     148                end
     149            end
     150            for t = 1:size(A, 1)
     151                if ~all(reshape(A(t,:,:) == 255, [], 1))
     152                    break;
     153                end
     154            end
     155            for b = size(A, 1):-1:t
     156                if ~all(reshape(A(b,:,:) == 255, [], 1))
     157                    break;
     158                end
     159            end
     160            bcol = uint8(median(single([reshape(A(:,[l r],:), [], size(A, 3)); reshape(A([t b],:,:), [], size(A, 3))]), 1));
     161            for c = 1:size(A, 3)
     162                A(:,[1:l-1, r+1:end],c) = bcol(c);
     163                A([1:t-1, b+1:end],:,c) = bcol(c);
     164            end
     165        end
    102166    else
    103         for l = 1:size(A, 2)
    104             if ~all(reshape(A(:,l,:) == 255, [], 1))
    105                 break;
    106             end
    107         end
    108         for r = size(A, 2):-1:l
    109             if ~all(reshape(A(:,r,:) == 255, [], 1))
    110                 break;
    111             end
    112         end
    113         for t = 1:size(A, 1)
    114             if ~all(reshape(A(t,:,:) == 255, [], 1))
    115                 break;
    116             end
    117         end
    118         for b = size(A, 1):-1:t
    119             if ~all(reshape(A(b,:,:) == 255, [], 1))
    120                 break;
    121             end
    122         end
    123         bcol = uint8(median(single([reshape(A(:,[l r],:), [], size(A, 3)); reshape(A([t b],:,:), [], size(A, 3))]), 1));
    124         for c = 1:size(A, 3)
    125             A(:,[1:l-1, r+1:end],c) = bcol(c);
    126             A([1:t-1, b+1:end],:,c) = bcol(c);
    127         end
    128     end
    129 else
    130     if nargin < 3
    131         renderer = '-opengl';
    132     end
    133     err = false;
    134     % Set paper size
    135     old_pos_mode = get(fig, 'PaperPositionMode');
    136     old_orientation = get(fig, 'PaperOrientation');
    137     set(fig, 'PaperPositionMode', 'auto', 'PaperOrientation', 'portrait');
    138     try
    139         % Print to tiff file
    140         print(fig, renderer, res_str, '-dtiff', tmp_nam);
    141         % Read in the printed file
    142         A = imread(tmp_nam);
    143         % Delete the temporary file
    144         delete(tmp_nam);
    145     catch ex
    146         err = true;
    147     end
    148     % Reset paper size
    149     set(fig, 'PaperPositionMode', old_pos_mode, 'PaperOrientation', old_orientation);
    150     % Throw any error that occurred
    151     if err
    152         rethrow(ex);
    153     end
    154     % Set the background color
    155     if isequal(bcol, 'none')
    156         bcol = [];
    157     else
    158         bcol = bcol * 255;
    159         if isequal(bcol, round(bcol))
    160             bcol = uint8(bcol);
    161         else
    162             bcol = squeeze(A(1,1,:));
    163         end
    164     end
    165 end
    166 % Check the output size is correct
    167 if isequal(res, round(res))
    168     px = [px([4 3])*res 3];
    169     if ~isequal(size(A), px)
    170         % Correct the output size
    171         A = A(1:min(end,px(1)),1:min(end,px(2)),:);
    172     end
    173 end
     167        if nargin < 3
     168            renderer = '-opengl';
     169        end
     170        err = false;
     171        % Set paper size
     172        old_pos_mode = get(fig, 'PaperPositionMode');
     173        old_orientation = get(fig, 'PaperOrientation');
     174        set(fig, 'PaperPositionMode', 'auto', 'PaperOrientation', 'portrait');
     175        try
     176            % Workaround for issue #69: patches with LineWidth==0.75 appear wide (internal bug in Matlab's print() function)
     177            fp = [];  % in case we get an error below
     178            fp = findall(fig, 'Type','patch', 'LineWidth',0.75);
     179            set(fp, 'LineWidth',0.5);
     180            % Fix issue #83: use numeric handles in HG1
     181            if ~using_hg2(fig),  fig = double(fig);  end
     182            % Print to tiff file
     183            print(fig, renderer, res_str, '-dtiff', tmp_nam);
     184            % Read in the printed file
     185            A = imread(tmp_nam);
     186            % Delete the temporary file
     187            delete(tmp_nam);
     188        catch ex
     189            err = true;
     190        end
     191        set(fp, 'LineWidth',0.75);  % restore original figure appearance
     192        % Reset paper size
     193        set(fig, 'PaperPositionMode', old_pos_mode, 'PaperOrientation', old_orientation);
     194        % Throw any error that occurred
     195        if err
     196            % Display suggested workarounds to internal print() error (issue #16)
     197            fprintf(2, 'An error occured with Matlab''s builtin print function.\nTry setting the figure Renderer to ''painters'' or use opengl(''software'').\n\n');
     198            rethrow(ex);
     199        end
     200        % Set the background color
     201        if isequal(bcol, 'none')
     202            bcol = [];
     203        else
     204            bcol = bcol * 255;
     205            if isequal(bcol, round(bcol))
     206                bcol = uint8(bcol);
     207            else
     208                bcol = squeeze(A(1,1,:));
     209            end
     210        end
     211    end
     212    % Check the output size is correct
     213    if isequal(res, round(res))
     214        px = round([px([4 3])*res 3]);  % round() to avoid an indexing warning below
     215        if ~isequal(size(A), px)
     216            % Correct the output size
     217            A = A(1:min(end,px(1)),1:min(end,px(2)),:);
     218        end
     219    end
    174220end
    175221
    176222% Function to return (and create, where necessary) the font path
    177223function fp = font_path()
    178 fp = user_string('gs_font_path');
    179 if ~isempty(fp)
    180     return
     224    fp = user_string('gs_font_path');
     225    if ~isempty(fp)
     226        return
     227    end
     228    % Create the path
     229    % Start with the default path
     230    fp = getenv('GS_FONTPATH');
     231    % Add on the typical directories for a given OS
     232    if ispc
     233        if ~isempty(fp)
     234            fp = [fp ';'];
     235        end
     236        fp = [fp getenv('WINDIR') filesep 'Fonts'];
     237    else
     238        if ~isempty(fp)
     239            fp = [fp ':'];
     240        end
     241        fp = [fp '/usr/share/fonts:/usr/local/share/fonts:/usr/share/fonts/X11:/usr/local/share/fonts/X11:/usr/share/fonts/truetype:/usr/local/share/fonts/truetype'];
     242    end
     243    user_string('gs_font_path', fp);
    181244end
    182 % Create the path
    183 % Start with the default path
    184 fp = getenv('GS_FONTPATH');
    185 % Add on the typical directories for a given OS
    186 if ispc
    187     if ~isempty(fp)
    188         fp = [fp ';'];
    189     end
    190     fp = [fp getenv('WINDIR') filesep 'Fonts'];
    191 else
    192     if ~isempty(fp)
    193         fp = [fp ':'];
    194     end
    195     fp = [fp '/usr/share/fonts:/usr/local/share/fonts:/usr/share/fonts/X11:/usr/local/share/fonts/X11:/usr/share/fonts/truetype:/usr/local/share/fonts/truetype'];
    196 end
    197 user_string('gs_font_path', fp);
    198 end
  • issm/trunk-jpl/externalpackages/export_fig/print2eps.m

    r19993 r21315  
     1function print2eps(name, fig, export_options, varargin)
    12%PRINT2EPS  Prints figures to eps with improved line styles
    23%
     
    45%   print2eps filename
    56%   print2eps(filename, fig_handle)
    6 %   print2eps(filename, fig_handle, bb_padding)
    7 %   print2eps(filename, fig_handle, bb_padding, options)
     7%   print2eps(filename, fig_handle, export_options)
     8%   print2eps(filename, fig_handle, export_options, print_options)
    89%
    910% This function saves a figure as an eps file, with two improvements over
    1011% MATLAB's print command. First, it improves the line style, making dashed
    11 % lines more like those on screen and giving grid lines their own dotted
    12 % style. Secondly, it substitutes original font names back into the eps
    13 % file, where these have been changed by MATLAB, for up to 11 different
    14 % fonts.
     12% lines more like those on screen and giving grid lines a dotted line style.
     13% Secondly, it substitutes original font names back into the eps file,
     14% where these have been changed by MATLAB, for up to 11 different fonts.
    1515%
    1616%IN:
     
    2020%              not specified, the figure is saved in the current directory.
    2121%   fig_handle - The handle of the figure to be saved. Default: gcf().
    22 %   bb_padding - Scalar value of amount of padding to add to border around
    23 %                the figure, in points. Can be negative as well as
    24 %                positive. Default: 0.
    25 %   options - Additional parameter strings to be passed to print.
    26 
    27 % Copyright (C) Oliver Woodford 2008-2014
     22%   export_options - array or struct of optional scalar values:
     23%       bb_padding - Scalar value of amount of padding to add to border around
     24%                    the cropped image, in points (if >1) or percent (if <1).
     25%                    Can be negative as well as positive; Default: 0
     26%       crop       - Cropping flag. Deafult: 0
     27%       fontswap   - Whether to swap non-default fonts in figure. Default: true
     28%       renderer   - Renderer used to generate bounding-box. Default: 'opengl'
     29%       crop_amounts - 4-element vector of crop amounts: [top,right,bottom,left]
     30%                    (available only via the struct alternative)
     31%   print_options - Additional parameter strings to be passed to the print command
     32
     33%{
     34% Copyright (C) Oliver Woodford 2008-2014, Yair Altman 2015-
    2835
    2936% The idea of editing the EPS file to change line styles comes from Jiro
     
    3138% The idea of changing dash length with line width came from comments on
    3239% fex id: 5743, but the implementation is mine :)
    33 
    34 % 14/11/2011: Fix a MATLAB bug rendering black or white text incorrectly.
    35 %             Thanks to Mathieu Morlighem for reporting the issue and
    36 %             obtaining a fix from TMW.
     40%}
     41%{
     42% 14/11/11: Fix a MATLAB bug rendering black or white text incorrectly.
     43%           Thanks to Mathieu Morlighem for reporting the issue and
     44%           obtaining a fix from TMW.
    3745% 08/12/11: Added ability to correct fonts. Several people have requested
    3846%           this at one time or another, and also pointed me to printeps
     
    5765%           issue.
    5866% 13/08/13: Fix MATLAB feature of not exporting white lines correctly.
    59 %           Thanks to Sebastian Heßlinger for reporting it.
    60 
    61 function print2eps(name, fig, bb_padding, varargin)
    62 options = {'-depsc2'};
    63 if nargin > 3
    64     options = [options varargin];
    65 elseif nargin < 3
    66     bb_padding = 0;
    67     if nargin < 2
    68         fig = gcf();
    69     end
     67%           Thanks to Sebastian Hesslinger for reporting it.
     68% 24/02/15: Fix for Matlab R2014b bug (issue #31): LineWidths<0.75 are not
     69%           set in the EPS (default line width is used)
     70% 25/02/15: Fixed issue #32: BoundingBox problem caused uncropped EPS/PDF files
     71% 05/03/15: Fixed issue #43: Inability to perform EPS file post-processing
     72% 06/03/15: Improved image padding & cropping thanks to Oscar Hartogensis
     73% 21/03/15: Fixed edge-case of missing handles having a 'FontName' property
     74% 26/03/15: Attempt to fix issue #45: white lines in subplots do not print correctly
     75% 27/03/15: Attempt to fix issue #44: white artifact lines appearing in patch exports
     76% 30/03/15: Fixed issue #52: improved performance on HG2 (R2014b+)
     77% 09/04/15: Comment blocks consolidation and minor code cleanup (no real code change)
     78% 12/04/15: Fixed issue #56: bad cropping
     79% 14/04/15: Workaround for issue #45: lines in image subplots are exported in invalid color
     80% 07/07/15: Added option to avoid font-swapping in EPS/PDF
     81% 07/07/15: Fixed issue #83: use numeric handles in HG1
     82% 22/07/15: Fixed issue #91 (thanks to Carlos Moffat)
     83% 28/09/15: Fixed issue #108 (thanks to JacobD10)
     84% 01/11/15: Fixed issue #112: optional renderer for bounding-box computation (thanks to Jesús Pestana Puerta)
     85% 21/02/16: Enabled specifying non-automated crop amounts
     86% 22/02/16: Better support + backward compatibility for transparency (issue #108)
     87% 10/06/16: Fixed issue #159: text handles get cleared by Matlab in the print() command
     88% 12/06/16: Improved the fix for issue #159 (in the previous commit)
     89% 12/06/16: Fixed issue #158: transparent patch color in PDF/EPS
     90%}
     91
     92    options = {'-loose'};
     93    if nargin > 3
     94        options = [options varargin];
     95    elseif nargin < 3
     96        export_options = 0;
     97        if nargin < 2
     98            fig = gcf();
     99        end
     100    end
     101
     102    % Retrieve padding, crop & font-swap values
     103    crop_amounts = nan(1,4);  % auto-crop all 4 sides by default
     104    if isstruct(export_options)
     105        try fontswap     = export_options.fontswap;     catch, fontswap = true;     end
     106        try bb_crop      = export_options.crop;         catch, bb_crop = 0;         end
     107        try crop_amounts = export_options.crop_amounts; catch,                      end
     108        try bb_padding   = export_options.bb_padding;   catch, bb_padding = 0;      end
     109        try renderer     = export_options.rendererStr;  catch, renderer = 'opengl'; end  % fix for issue #110
     110        if renderer(1)~='-',  renderer = ['-' renderer];  end
     111    else
     112        if numel(export_options) > 2  % font-swapping
     113            fontswap = export_options(3);
     114        else
     115            fontswap = true;
     116        end
     117        if numel(export_options) > 1  % cropping
     118            bb_crop = export_options(2);
     119        else
     120            bb_crop = 0;  % scalar value, so use default bb_crop value of 0
     121        end
     122        if numel(export_options) > 0  % padding
     123            bb_padding = export_options(1);
     124        else
     125            bb_padding = 0;
     126        end
     127        renderer = '-opengl';
     128    end
     129
     130    % Construct the filename
     131    if numel(name) < 5 || ~strcmpi(name(end-3:end), '.eps')
     132        name = [name '.eps']; % Add the missing extension
     133    end
     134
     135    % Set paper size
     136    old_pos_mode = get(fig, 'PaperPositionMode');
     137    old_orientation = get(fig, 'PaperOrientation');
     138    set(fig, 'PaperPositionMode', 'auto', 'PaperOrientation', 'portrait');
     139
     140    % Find all the used fonts in the figure
     141    font_handles = findall(fig, '-property', 'FontName');
     142    fonts = get(font_handles, 'FontName');
     143    if isempty(fonts)
     144        fonts = {};
     145    elseif ~iscell(fonts)
     146        fonts = {fonts};
     147    end
     148
     149    % Map supported font aliases onto the correct name
     150    fontsl = lower(fonts);
     151    for a = 1:numel(fonts)
     152        f = fontsl{a};
     153        f(f==' ') = [];
     154        switch f
     155            case {'times', 'timesnewroman', 'times-roman'}
     156                fontsl{a} = 'times-roman';
     157            case {'arial', 'helvetica'}
     158                fontsl{a} = 'helvetica';
     159            case {'newcenturyschoolbook', 'newcenturyschlbk'}
     160                fontsl{a} = 'newcenturyschlbk';
     161            otherwise
     162        end
     163    end
     164    fontslu = unique(fontsl);
     165
     166    % Determine the font swap table
     167    if fontswap
     168        matlab_fonts = {'Helvetica', 'Times-Roman', 'Palatino', 'Bookman', 'Helvetica-Narrow', 'Symbol', ...
     169                        'AvantGarde', 'NewCenturySchlbk', 'Courier', 'ZapfChancery', 'ZapfDingbats'};
     170        matlab_fontsl = lower(matlab_fonts);
     171        require_swap = find(~ismember(fontslu, matlab_fontsl));
     172        unused_fonts = find(~ismember(matlab_fontsl, fontslu));
     173        font_swap = cell(3, min(numel(require_swap), numel(unused_fonts)));
     174        fonts_new = fonts;
     175        for a = 1:size(font_swap, 2)
     176            font_swap{1,a} = find(strcmp(fontslu{require_swap(a)}, fontsl));
     177            font_swap{2,a} = matlab_fonts{unused_fonts(a)};
     178            font_swap{3,a} = fonts{font_swap{1,a}(1)};
     179            fonts_new(font_swap{1,a}) = font_swap(2,a);
     180        end
     181    else
     182        font_swap = [];
     183    end
     184
     185    % Swap the fonts
     186    if ~isempty(font_swap)
     187        fonts_size = get(font_handles, 'FontSize');
     188        if iscell(fonts_size)
     189            fonts_size = cell2mat(fonts_size);
     190        end
     191        M = false(size(font_handles));
     192
     193        % Loop because some changes may not stick first time, due to listeners
     194        c = 0;
     195        update = zeros(1000, 1);
     196        for b = 1:10 % Limit number of loops to avoid infinite loop case
     197            for a = 1:numel(M)
     198                M(a) = ~isequal(get(font_handles(a), 'FontName'), fonts_new{a}) || ~isequal(get(font_handles(a), 'FontSize'), fonts_size(a));
     199                if M(a)
     200                    set(font_handles(a), 'FontName', fonts_new{a}, 'FontSize', fonts_size(a));
     201                    c = c + 1;
     202                    update(c) = a;
     203                end
     204            end
     205            if ~any(M)
     206                break;
     207            end
     208        end
     209
     210        % Compute the order to revert fonts later, without the need of a loop
     211        [update, M] = unique(update(1:c));
     212        [M, M] = sort(M);
     213        update = reshape(update(M), 1, []);
     214    end
     215
     216    % MATLAB bug fix - black and white text can come out inverted sometimes
     217    % Find the white and black text
     218    black_text_handles = findall(fig, 'Type', 'text', 'Color', [0 0 0]);
     219    white_text_handles = findall(fig, 'Type', 'text', 'Color', [1 1 1]);
     220    % Set the font colors slightly off their correct values
     221    set(black_text_handles, 'Color', [0 0 0] + eps);
     222    set(white_text_handles, 'Color', [1 1 1] - eps);
     223
     224    % MATLAB bug fix - white lines can come out funny sometimes
     225    % Find the white lines
     226    white_line_handles = findall(fig, 'Type', 'line', 'Color', [1 1 1]);
     227    % Set the line color slightly off white
     228    set(white_line_handles, 'Color', [1 1 1] - 0.00001);
     229
     230    % Workaround for issue #45: lines in image subplots are exported in invalid color
     231    % In this case the -depsc driver solves the problem, but then all the other workarounds
     232    % below (for all the other issues) will fail, so it's better to let the user decide by
     233    % just issuing a warning and accepting the '-depsc' input parameter
     234    epsLevel2 = ~any(strcmpi(options,'-depsc'));
     235    if epsLevel2
     236        % Use -depsc2 (EPS color level-2) if -depsc (EPS color level-3) was not specifically requested
     237        options{end+1} = '-depsc2';
     238        % Issue a warning if multiple images & lines were found in the figure, and HG1 with painters renderer is used
     239        isPainters = any(strcmpi(options,'-painters'));
     240        if isPainters && ~using_hg2 && numel(findall(fig,'Type','image'))>1 && ~isempty(findall(fig,'Type','line'))
     241            warning('YMA:export_fig:issue45', ...
     242                    ['Multiple images & lines detected. In such cases, the lines might \n' ...
     243                     'appear with an invalid color due to an internal MATLAB bug (fixed in R2014b). \n' ...
     244                     'Possible workaround: add a ''-depsc'' or ''-opengl'' parameter to the export_fig command.']);
     245        end
     246    end
     247
     248    % Fix issue #83: use numeric handles in HG1
     249    if ~using_hg2(fig),  fig = double(fig);  end
     250
     251    % Workaround for when transparency is lost through conversion fig>EPS>PDF (issue #108)
     252    % Replace transparent patch RGB values with an ID value (rare chance that ID color is being used already)
     253    if using_hg2
     254        origAlphaColors = eps_maintainAlpha(fig);
     255    end
     256
     257    % Print to eps file
     258    print(fig, options{:}, name);
     259
     260    % Do post-processing on the eps file
     261    try
     262        % Read the EPS file into memory
     263        fstrm = read_write_entire_textfile(name);
     264    catch
     265        fstrm = '';
     266    end
     267
     268    % Restore colors for transparent patches/lines and apply the
     269    % setopacityalpha setting in the EPS file (issue #108)
     270    if using_hg2
     271        [~,fstrm,foundFlags] = eps_maintainAlpha(fig, fstrm, origAlphaColors);
     272
     273        % If some of the transparencies were not found in the EPS file, then rerun the
     274        % export with only the found transparencies modified (backward compatibility)
     275        if ~isempty(fstrm) && ~all(foundFlags)
     276            foundIdx = find(foundFlags);
     277            for objIdx = 1 : sum(foundFlags)
     278                colorsIdx = foundIdx(objIdx);
     279                colorsData = origAlphaColors{colorsIdx};
     280                hObj     = colorsData{1};
     281                propName = colorsData{2};
     282                newColor = colorsData{4};
     283                hObj.(propName).ColorData = newColor;
     284            end
     285            delete(name);
     286            print(fig, options{:}, name);
     287            fstrm = read_write_entire_textfile(name);
     288            [~,fstrm] = eps_maintainAlpha(fig, fstrm, origAlphaColors(foundFlags));
     289        end
     290    end
     291
     292    % Fix for Matlab R2014b bug (issue #31): LineWidths<0.75 are not set in the EPS (default line width is used)
     293    try
     294        if ~isempty(fstrm) && using_hg2(fig)
     295            % Convert miter joins to line joins
     296            %fstrm = regexprep(fstrm, '\n10.0 ML\n', '\n1 LJ\n');
     297            % This is faster (the original regexprep could take many seconds when the axes contains many lines):
     298            fstrm = strrep(fstrm, sprintf('\n10.0 ML\n'), sprintf('\n1 LJ\n'));
     299
     300            % In HG2, grid lines and axes Ruler Axles have a default LineWidth of 0.5 => replace en-bulk (assume that 1.0 LineWidth = 1.333 LW)
     301            %   hAxes=gca; hAxes.YGridHandle.LineWidth, hAxes.YRuler.Axle.LineWidth
     302            %fstrm = regexprep(fstrm, '(GC\n2 setlinecap\n1 LJ)\nN', '$1\n0.667 LW\nN');
     303            % This is faster:
     304            fstrm = strrep(fstrm, sprintf('GC\n2 setlinecap\n1 LJ\nN'), sprintf('GC\n2 setlinecap\n1 LJ\n0.667 LW\nN'));
     305
     306            % This is more accurate but *MUCH* slower (issue #52)
     307            %{
     308            % Modify all thin lines in the figure to have 10x LineWidths
     309            hLines = findall(fig,'Type','line');
     310            hThinLines = [];
     311            for lineIdx = 1 : numel(hLines)
     312                thisLine = hLines(lineIdx);
     313                if thisLine.LineWidth < 0.75 && strcmpi(thisLine.Visible,'on')
     314                    hThinLines(end+1) = thisLine; %#ok<AGROW>
     315                    thisLine.LineWidth = thisLine.LineWidth * 10;
     316                end
     317            end
     318
     319            % If any thin lines were found
     320            if ~isempty(hThinLines)
     321                % Prepare an EPS with large-enough line widths
     322                print(fig, options{:}, name);
     323                % Restore the original LineWidths in the figure
     324                for lineIdx = 1 : numel(hThinLines)
     325                    thisLine = handle(hThinLines(lineIdx));
     326                    thisLine.LineWidth = thisLine.LineWidth / 10;
     327                end
     328
     329                % Compare the original and the new EPS files and correct the original stream's LineWidths
     330                fstrm_new = read_write_entire_textfile(name);
     331                idx = 500;  % skip heading with its possibly-different timestamp
     332                markerStr = sprintf('10.0 ML\nN');
     333                markerLen = length(markerStr);
     334                while ~isempty(idx) && idx < length(fstrm)
     335                    lastIdx = min(length(fstrm), length(fstrm_new));
     336                    delta = fstrm(idx+1:lastIdx) - fstrm_new(idx+1:lastIdx);
     337                    idx = idx + find(delta,1);
     338                    if ~isempty(idx) && ...
     339                            isequal(fstrm(idx-markerLen+1:idx), markerStr) && ...
     340                            ~isempty(regexp(fstrm_new(idx-markerLen+1:idx+12),'10.0 ML\n[\d\.]+ LW\nN')) %#ok<RGXP1>
     341                        value = str2double(regexprep(fstrm_new(idx:idx+12),' .*',''));
     342                        if isnan(value), break; end  % something's wrong... - bail out
     343                        newStr = sprintf('%0.3f LW\n',value/10);
     344                        fstrm = [fstrm(1:idx-1) newStr fstrm(idx:end)];
     345                        idx = idx + 12;
     346                    else
     347                        break;
     348                    end
     349                end
     350            end
     351            %}
     352
     353            % This is much faster although less accurate: fix all non-gray lines to have a LineWidth of 0.75 (=1 LW)
     354            % Note: This will give incorrect LineWidth of 075 for lines having LineWidth<0.75, as well as for non-gray grid-lines (if present)
     355            %       However, in practice these edge-cases are very rare indeed, and the difference in LineWidth should not be noticeable
     356            %fstrm = regexprep(fstrm, '([CR]C\n2 setlinecap\n1 LJ)\nN', '$1\n1 LW\nN');
     357            % This is faster (the original regexprep could take many seconds when the axes contains many lines):
     358            fstrm = strrep(fstrm, sprintf('\n2 setlinecap\n1 LJ\nN'), sprintf('\n2 setlinecap\n1 LJ\n1 LW\nN'));
     359        end
     360    catch err
     361        fprintf(2, 'Error fixing LineWidths in EPS file: %s\n at %s:%d\n', err.message, err.stack(1).file, err.stack(1).line);
     362    end
     363
     364    % Reset the font and line colors
     365    try
     366        set(black_text_handles, 'Color', [0 0 0]);
     367        set(white_text_handles, 'Color', [1 1 1]);
     368    catch
     369        % Fix issue #159: redo findall() '*text_handles'
     370        black_text_handles = findall(fig, 'Type', 'text', 'Color', [0 0 0]+eps);
     371        white_text_handles = findall(fig, 'Type', 'text', 'Color', [1 1 1]-eps);
     372        set(black_text_handles, 'Color', [0 0 0]);
     373        set(white_text_handles, 'Color', [1 1 1]);
     374    end
     375    set(white_line_handles, 'Color', [1 1 1]);
     376
     377    % Reset paper size
     378    set(fig, 'PaperPositionMode', old_pos_mode, 'PaperOrientation', old_orientation);
     379
     380    % Reset the font names in the figure
     381    if ~isempty(font_swap)
     382        for a = update
     383            set(font_handles(a), 'FontName', fonts{a}, 'FontSize', fonts_size(a));
     384        end
     385    end
     386
     387    % Bail out if EPS post-processing is not possible
     388    if isempty(fstrm)
     389        warning('Loading EPS file failed, so unable to perform post-processing. This is usually because the figure contains a large number of patch objects. Consider exporting to a bitmap format in this case.');
     390        return
     391    end
     392
     393    % Replace the font names
     394    if ~isempty(font_swap)
     395        for a = 1:size(font_swap, 2)
     396            %fstrm = regexprep(fstrm, [font_swap{1,a} '-?[a-zA-Z]*\>'], font_swap{3,a}(~isspace(font_swap{3,a})));
     397            fstrm = regexprep(fstrm, font_swap{2,a}, font_swap{3,a}(~isspace(font_swap{3,a})));
     398        end
     399    end
     400
     401    % Move the bounding box to the top of the file (HG2 only), or fix the line styles (HG1 only)
     402    if using_hg2(fig)
     403        % Move the bounding box to the top of the file (HG2 only)
     404        [s, e] = regexp(fstrm, '%%BoundingBox: [^%]*%%');
     405        if numel(s) == 2
     406            fstrm = fstrm([1:s(1)-1 s(2):e(2)-2 e(1)-1:s(2)-1 e(2)-1:end]);
     407        end
     408    else
     409        % Fix the line styles (HG1 only)
     410        fstrm = fix_lines(fstrm);
     411    end
     412
     413    % Apply the bounding box padding & cropping, replacing Matlab's print()'s bounding box
     414    if bb_crop
     415        % Calculate a new bounding box based on a bitmap print using crop_border.m
     416        % 1. Determine the Matlab BoundingBox and PageBoundingBox
     417        [s,e] = regexp(fstrm, '%%BoundingBox: [^%]*%%'); % location BB in eps file
     418        if numel(s)==2, s=s(2); e=e(2); end
     419        aa = fstrm(s+15:e-3); % dimensions bb - STEP1
     420        bb_matlab = cell2mat(textscan(aa,'%f32%f32%f32%f32'));  % dimensions bb - STEP2
     421
     422        [s,e] = regexp(fstrm, '%%PageBoundingBox: [^%]*%%'); % location bb in eps file
     423        if numel(s)==2, s=s(2); e=e(2); end
     424        aa = fstrm(s+19:e-3); % dimensions bb - STEP1
     425        pagebb_matlab = cell2mat(textscan(aa,'%f32%f32%f32%f32'));  % dimensions bb - STEP2
     426
     427        % 2. Create a bitmap image and use crop_borders to create the relative
     428        %    bb with respect to the PageBoundingBox
     429        [A, bcol] = print2array(fig, 1, renderer);
     430        [aa, aa, aa, bb_rel] = crop_borders(A, bcol, bb_padding, crop_amounts);
     431
     432        % 3. Calculate the new Bounding Box
     433        pagew = pagebb_matlab(3)-pagebb_matlab(1);
     434        pageh = pagebb_matlab(4)-pagebb_matlab(2);
     435        %bb_new = [pagebb_matlab(1)+pagew*bb_rel(1) pagebb_matlab(2)+pageh*bb_rel(2) ...
     436        %          pagebb_matlab(1)+pagew*bb_rel(3) pagebb_matlab(2)+pageh*bb_rel(4)];
     437        bb_new = pagebb_matlab([1,2,1,2]) + [pagew,pageh,pagew,pageh].*bb_rel;  % clearer
     438        bb_offset = (bb_new-bb_matlab) + [-1,-1,1,1];  % 1px margin so that cropping is not TOO tight
     439
     440        % Apply the bounding box padding
     441        if bb_padding
     442            if abs(bb_padding)<1
     443                bb_padding = round((mean([bb_new(3)-bb_new(1) bb_new(4)-bb_new(2)])*bb_padding)/0.5)*0.5; % ADJUST BB_PADDING
     444            end
     445            add_padding = @(n1, n2, n3, n4) sprintf(' %d', str2double({n1, n2, n3, n4}) + [-bb_padding -bb_padding bb_padding bb_padding] + bb_offset);
     446        else
     447            add_padding = @(n1, n2, n3, n4) sprintf(' %d', str2double({n1, n2, n3, n4}) + bb_offset); % fix small but noticeable bounding box shift
     448        end
     449        fstrm = regexprep(fstrm, '%%BoundingBox:[ ]+([-]?\d+)[ ]+([-]?\d+)[ ]+([-]?\d+)[ ]+([-]?\d+)', '%%BoundingBox:${add_padding($1, $2, $3, $4)}');
     450    end
     451
     452    % Fix issue #44: white artifact lines appearing in patch exports
     453    % Note: the problem is due to the fact that Matlab's print() function exports patches
     454    %       as a combination of filled triangles, and a white line appears where the triangles touch
     455    % In the workaround below, we will modify such dual-triangles into a filled rectangle.
     456    % We are careful to only modify regexps that exactly match specific patterns - it's better to not
     457    % correct some white-line artifacts than to change the geometry of a patch, or to corrupt the EPS.
     458    %   e.g.: '0 -450 937 0 0 450 3 MP PP 937 0 0 -450 0 450 3 MP PP' => '0 -450 937 0 0 450 0 0 4 MP'
     459    fstrm = regexprep(fstrm, '\n([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) 3 MP\nPP\n\2 \1 \3 3 MP\nPP\n','\n$1 $2 $3 0 0 4 MP\nPP\n');
     460    fstrm = regexprep(fstrm, '\n([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) 3 MP\nPP\n\2 \3 \1 3 MP\nPP\n','\n$1 $2 $3 0 0 4 MP\nPP\n');
     461    fstrm = regexprep(fstrm, '\n([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) 3 MP\nPP\n\3 \1 \2 3 MP\nPP\n','\n$1 $2 $3 0 0 4 MP\nPP\n');
     462    fstrm = regexprep(fstrm, '\n([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) 3 MP\nPP\n\3 \2 \1 3 MP\nPP\n','\n$1 $2 $3 0 0 4 MP\nPP\n');
     463
     464    % Write out the fixed eps file
     465    read_write_entire_textfile(name, fstrm);
    70466end
    71 % Construct the filename
    72 if numel(name) < 5 || ~strcmpi(name(end-3:end), '.eps')
    73     name = [name '.eps']; % Add the missing extension
     467
     468function [StoredColors, fstrm, foundFlags] = eps_maintainAlpha(fig, fstrm, StoredColors)
     469    if nargin == 1  % in: convert transparency in Matlab figure into unique RGB colors
     470        hObjs = findall(fig); %findobj(fig,'Type','Area');
     471        StoredColors = {};
     472        propNames = {'Face','Edge'};
     473        for objIdx = 1:length(hObjs)
     474            hObj = hObjs(objIdx);
     475            for propIdx = 1 : numel(propNames)
     476                try
     477                    propName = propNames{propIdx};
     478                    if strcmp(hObj.(propName).ColorType, 'truecoloralpha')
     479                        nColors = length(StoredColors);
     480                        oldColor = hObj.(propName).ColorData;
     481                        newColor = uint8([101; 102+floor(nColors/255); mod(nColors,255); 255]);
     482                        StoredColors{end+1} = {hObj, propName, oldColor, newColor};
     483                        hObj.(propName).ColorData = newColor;
     484                    end
     485                catch
     486                    % Never mind - ignore (either doesn't have the property or cannot change it)
     487                end
     488            end
     489        end
     490    else  % restore transparency in Matlab figure by converting back from the unique RGBs
     491        %Find the transparent patches
     492        wasError = false;
     493        nColors = length(StoredColors);
     494        foundFlags = false(1,nColors);
     495        for objIdx = 1 : nColors
     496            colorsData = StoredColors{objIdx};
     497            hObj      = colorsData{1};
     498            propName  = colorsData{2};
     499            origColor = colorsData{3};
     500            newColor  = colorsData{4};
     501            try
     502                %Restore the EPS files patch color
     503                colorID   = num2str(round(double(newColor(1:3)') /255,3),'%.3g %.3g %.3g'); %ID for searching
     504                origRGB   = num2str(round(double(origColor(1:3)')/255,3),'%.3g %.3g %.3g'); %Replace with original color
     505                origAlpha = num2str(round(double(origColor(end)) /255,3),'%.3g'); %Convert alpha value for EPS
     506
     507                %Find and replace the RGBA values within the EPS text fstrm
     508                if strcmpi(propName,'Face')
     509                    oldStr = sprintf(['\n' colorID ' RC\nN\n']);
     510                    newStr = sprintf(['\n' origRGB ' RC\n' origAlpha ' .setopacityalpha true\nN\n']);
     511                else  %'Edge'
     512                    oldStr = sprintf(['\n' colorID ' RC\n1 LJ\n']);
     513                    newStr = sprintf(['\n' origRGB ' RC\n' origAlpha ' .setopacityalpha true\n']);
     514                end
     515                foundFlags(objIdx) = ~isempty(strfind(fstrm, oldStr));
     516                fstrm = strrep(fstrm, oldStr, newStr);
     517
     518                %Restore the figure object's original color
     519                hObj.(propName).ColorData = origColor;
     520            catch err
     521                % something is wrong - cannot restore transparent color...
     522                if ~wasError
     523                    fprintf(2, 'Error maintaining transparency in EPS file: %s\n at %s:%d\n', err.message, err.stack(1).file, err.stack(1).line);
     524                    wasError = true;
     525                end
     526            end
     527        end
     528    end
    74529end
    75 % Set paper size
    76 old_pos_mode = get(fig, 'PaperPositionMode');
    77 old_orientation = get(fig, 'PaperOrientation');
    78 set(fig, 'PaperPositionMode', 'auto', 'PaperOrientation', 'portrait');
    79 % Find all the used fonts in the figure
    80 font_handles = findall(fig, '-property', 'FontName');
    81 fonts = get(font_handles, 'FontName');
    82 if ~iscell(fonts)
    83     fonts = {fonts};
    84 end
    85 % Map supported font aliases onto the correct name
    86 fontsl = lower(fonts);
    87 for a = 1:numel(fonts)
    88     f = fontsl{a};
    89     f(f==' ') = [];
    90     switch f
    91         case {'times', 'timesnewroman', 'times-roman'}
    92             fontsl{a} = 'times-roman';
    93         case {'arial', 'helvetica'}
    94             fontsl{a} = 'helvetica';
    95         case {'newcenturyschoolbook', 'newcenturyschlbk'}
    96             fontsl{a} = 'newcenturyschlbk';
    97         otherwise
    98     end
    99 end
    100 fontslu = unique(fontsl);
    101 % Determine the font swap table
    102 matlab_fonts = {'Helvetica', 'Times-Roman', 'Palatino', 'Bookman', 'Helvetica-Narrow', 'Symbol', ...
    103                 'AvantGarde', 'NewCenturySchlbk', 'Courier', 'ZapfChancery', 'ZapfDingbats'};
    104 matlab_fontsl = lower(matlab_fonts);
    105 require_swap = find(~ismember(fontslu, matlab_fontsl));
    106 unused_fonts = find(~ismember(matlab_fontsl, fontslu));
    107 font_swap = cell(3, min(numel(require_swap), numel(unused_fonts)));
    108 fonts_new = fonts;
    109 for a = 1:size(font_swap, 2)
    110     font_swap{1,a} = find(strcmp(fontslu{require_swap(a)}, fontsl));
    111     font_swap{2,a} = matlab_fonts{unused_fonts(a)};
    112     font_swap{3,a} = fonts{font_swap{1,a}(1)};
    113     fonts_new(font_swap{1,a}) = {font_swap{2,a}};
    114 end
    115 % Swap the fonts
    116 if ~isempty(font_swap)
    117     fonts_size = get(font_handles, 'FontSize');
    118     if iscell(fonts_size)
    119         fonts_size = cell2mat(fonts_size);
    120     end
    121     M = false(size(font_handles));
    122     % Loop because some changes may not stick first time, due to listeners
    123     c = 0;
    124     update = zeros(1000, 1);
    125     for b = 1:10 % Limit number of loops to avoid infinite loop case
    126         for a = 1:numel(M)
    127             M(a) = ~isequal(get(font_handles(a), 'FontName'), fonts_new{a}) || ~isequal(get(font_handles(a), 'FontSize'), fonts_size(a));
    128             if M(a)
    129                 set(font_handles(a), 'FontName', fonts_new{a}, 'FontSize', fonts_size(a));
    130                 c = c + 1;
    131                 update(c) = a;
    132             end
    133         end
    134         if ~any(M)
    135             break;
    136         end
    137     end
    138     % Compute the order to revert fonts later, without the need of a loop
    139     [update, M] = unique(update(1:c));
    140     [M, M] = sort(M);
    141     update = reshape(update(M), 1, []);
    142 end
    143 % MATLAB bug fix - black and white text can come out inverted sometimes
    144 % Find the white and black text
    145 white_text_handles = findobj(fig, 'Type', 'text');
    146 M = get(white_text_handles, 'Color');
    147 if iscell(M)
    148     M = cell2mat(M);
    149 end
    150 M = sum(M, 2);
    151 black_text_handles = white_text_handles(M == 0);
    152 white_text_handles = white_text_handles(M == 3);
    153 % Set the font colors slightly off their correct values
    154 set(black_text_handles, 'Color', [0 0 0] + eps);
    155 set(white_text_handles, 'Color', [1 1 1] - eps);
    156 % MATLAB bug fix - white lines can come out funny sometimes
    157 % Find the white lines
    158 white_line_handles = findobj(fig, 'Type', 'line');
    159 M = get(white_line_handles, 'Color');
    160 if iscell(M)
    161     M = cell2mat(M);
    162 end
    163 white_line_handles = white_line_handles(sum(M, 2) == 3);
    164 % Set the line color slightly off white
    165 set(white_line_handles, 'Color', [1 1 1] - 0.00001);
    166 % Print to eps file
    167 print(fig, options{:}, name);
    168 % Reset the font and line colors
    169 set(black_text_handles, 'Color', [0 0 0]);
    170 set(white_text_handles, 'Color', [1 1 1]);
    171 set(white_line_handles, 'Color', [1 1 1]);
    172 % Reset paper size
    173 set(fig, 'PaperPositionMode', old_pos_mode, 'PaperOrientation', old_orientation);
    174 % Reset the font names in the figure
    175 if ~isempty(font_swap)
    176     for a = update
    177         set(font_handles(a), 'FontName', fonts{a}, 'FontSize', fonts_size(a));
    178     end
    179 end
    180 % Do post-processing on the eps file
    181 try
    182     fstrm = read_write_entire_textfile(name);
    183 catch
    184     warning('Loading EPS file failed, so unable to perform post-processing. This is usually because the figure contains a large number of patch objects. Consider exporting to a bitmap format in this case.');
    185     return
    186 end
    187 % Replace the font names
    188 if ~isempty(font_swap)
    189     for a = 1:size(font_swap, 2)
    190         %fstrm = regexprep(fstrm, [font_swap{1,a} '-?[a-zA-Z]*\>'], font_swap{3,a}(~isspace(font_swap{3,a})));
    191         fstrm = regexprep(fstrm, font_swap{2,a}, font_swap{3,a}(~isspace(font_swap{3,a})));
    192     end
    193 end
    194 if using_hg2(fig)
    195     % Convert miter joins to line joins
    196     fstrm = regexprep(fstrm, '10.0 ML\n', '1 LJ\n');
    197     % Move the bounding box to the top of the file
    198     [s, e] = regexp(fstrm, '%%BoundingBox: [\w\s()]*%%');
    199     if numel(s) == 2
    200         fstrm = fstrm([1:s(1)-1 s(2):e(2)-2 e(1)-1:s(2)-1 e(2)-1:end]);
    201     end
    202 else
    203     % Fix the line styles
    204     fstrm = fix_lines(fstrm);
    205 end
    206 % Apply the bounding box padding
    207 if bb_padding
    208     add_padding = @(n1, n2, n3, n4) sprintf(' %d', str2double({n1, n2, n3, n4}) + [-bb_padding -bb_padding bb_padding bb_padding]);
    209     fstrm = regexprep(fstrm, '%%BoundingBox:[ ]+([-]?\d+)[ ]+([-]?\d+)[ ]+([-]?\d+)[ ]+([-]?\d+)', '%%BoundingBox:${add_padding($1, $2, $3, $4)}');
    210 end
    211 % Write out the fixed eps file
    212 read_write_entire_textfile(name, fstrm);
    213 end
  • issm/trunk-jpl/externalpackages/export_fig/user_string.m

    r19993 r21315  
     1function string = user_string(string_name, string)
    12%USER_STRING  Get/set a user specific string
    23%
    34% Examples:
    4 %   string = user_string(string_name)
    5 %   saved = user_string(string_name, new_string)
     5%   string  = user_string(string_name)
     6%   isSaved = user_string(string_name, new_string)
    67%
    78% Function to get and set a string in a system or user specific file. This
    89% enables, for example, system specific paths to binaries to be saved.
    910%
     11% The specified string will be saved in a file named <string_name>.txt,
     12% either in a subfolder named .ignore under this file's folder, or in the
     13% user's prefdir folder (in case this file's folder is non-writable).
     14%
    1015% IN:
    11 %   string_name - String containing the name of the string required. The
    12 %                 string is extracted from a file called (string_name).txt,
    13 %                 stored in the same directory as user_string.m.
    14 %   new_string - The new string to be saved under the name given by
    15 %                string_name.
     16%   string_name - String containing the name of the string required, which
     17%                 sets the filename storing the string: <string_name>.txt
     18%   new_string  - The new string to be saved in the <string_name>.txt file
    1619%
    1720% OUT:
    18 %   string - The currently saved string. Default: ''.
    19 %   saved - Boolean indicating whether the save was succesful
     21%   string  - The currently saved string. Default: ''
     22%   isSaved - Boolean indicating whether the save was succesful
    2023
    21 % Copyright (C) Oliver Woodford 2011-2013
     24% Copyright (C) Oliver Woodford 2011-2014, Yair Altman 2015-
    2225
    2326% This method of saving paths avoids changing .m files which might be in a
     
    2831
    2932% 10/01/2013 - Access files in text, not binary mode, as latter can cause
    30 % errors. Thanks to Christian for pointing this out.
     33%              errors. Thanks to Christian for pointing this out.
     34% 29/05/2015 - Save file in prefdir if current folder is non-writable (issue #74)
    3135
    32 function string = user_string(string_name, string)
    33 if ~ischar(string_name)
    34     error('string_name must be a string.');
    35 end
    36 % Create the full filename
    37 string_name = fullfile(fileparts(mfilename('fullpath')), '.ignore', [string_name '.txt']);
    38 if nargin > 1
    39     % Set string
    40     if ~ischar(string)
    41         error('new_string must be a string.');
     36    if ~ischar(string_name)
     37        error('string_name must be a string.');
    4238    end
    43     % Make sure the save directory exists
    44     dname = fileparts(string_name);
    45     if ~exist(dname, 'dir')
    46         % Create the directory
    47         try
    48             if ~mkdir(dname)               
     39    % Create the full filename
     40    fname = [string_name '.txt'];
     41    dname = fullfile(fileparts(mfilename('fullpath')), '.ignore');
     42    file_name = fullfile(dname, fname);
     43    if nargin > 1
     44        % Set string
     45        if ~ischar(string)
     46            error('new_string must be a string.');
     47        end
     48        % Make sure the save directory exists
     49        %dname = fileparts(file_name);
     50        if ~exist(dname, 'dir')
     51            % Create the directory
     52            try
     53                if ~mkdir(dname)
     54                    string = false;
     55                    return
     56                end
     57            catch
    4958                string = false;
    5059                return
    5160            end
     61            % Make it hidden
     62            try
     63                fileattrib(dname, '+h');
     64            catch
     65            end
     66        end
     67        % Write the file
     68        fid = fopen(file_name, 'wt');
     69        if fid == -1
     70            % file cannot be created/updated - use prefdir if file does not already exist
     71            % (if file exists but is simply not writable, don't create a duplicate in prefdir)
     72            if ~exist(file_name,'file')
     73                file_name = fullfile(prefdir, fname);
     74                fid = fopen(file_name, 'wt');
     75            end
     76            if fid == -1
     77                string = false;
     78                return;
     79            end
     80        end
     81        try
     82            fprintf(fid, '%s', string);
    5283        catch
     84            fclose(fid);
    5385            string = false;
    5486            return
    5587        end
    56         % Make it hidden
    57         try
    58             fileattrib(dname, '+h');
    59         catch
     88        fclose(fid);
     89        string = true;
     90    else
     91        % Get string
     92        fid = fopen(file_name, 'rt');
     93        if fid == -1
     94            % file cannot be read, try to read the file in prefdir
     95            file_name = fullfile(prefdir, fname);
     96            fid = fopen(file_name, 'rt');
     97            if fid == -1
     98                string = '';
     99                return
     100            end
    60101        end
     102        string = fgetl(fid);
     103        fclose(fid);
    61104    end
    62     % Write the file
    63     fid = fopen(string_name, 'wt');
    64     if fid == -1
    65         string = false;
    66         return
    67     end
    68     try
    69         fprintf(fid, '%s', string);
    70     catch
    71         fclose(fid);
    72         string = false;
    73         return
    74     end
    75     fclose(fid);
    76     string = true;
    77 else
    78     % Get string
    79     fid = fopen(string_name, 'rt');
    80     if fid == -1
    81         string = '';
    82         return
    83     end
    84     string = fgetl(fid);
    85     fclose(fid);
    86105end
    87 end
  • issm/trunk-jpl/externalpackages/export_fig/using_hg2.m

    r19993 r21315  
    1 %USING_HG2 Determine if the HG2 graphics pipeline is used
     1%USING_HG2 Determine if the HG2 graphics engine is used
    22%
    33%   tf = using_hg2(fig)
     
    77%
    88%OUT:
    9 %   tf - boolean indicating whether the HG2 graphics pipeline is being used
     9%   tf - boolean indicating whether the HG2 graphics engine is being used
    1010%        (true) or not (false).
    1111
     12% 19/06/2015 - Suppress warning in R2015b; cache result for improved performance
     13% 06/06/2016 - Fixed issue #156 (bad return value in R2016b)
     14
    1215function tf = using_hg2(fig)
    13 try
    14     tf = ~graphicsversion(fig, 'handlegraphics');
    15 catch
    16     tf = false;
     16    persistent tf_cached
     17    if isempty(tf_cached)
     18        try
     19            if nargin < 1,  fig = figure('visible','off');  end
     20            oldWarn = warning('off','MATLAB:graphicsversion:GraphicsVersionRemoval');
     21            try
     22                % This generates a [supressed] warning in R2015b:
     23                tf = ~graphicsversion(fig, 'handlegraphics');
     24            catch
     25                tf = ~verLessThan('matlab','8.4');  % =R2014b
     26            end
     27            warning(oldWarn);
     28        catch
     29            tf = false;
     30        end
     31        if nargin < 1,  delete(fig);  end
     32        tf_cached = tf;
     33    else
     34        tf = tf_cached;
     35    end
    1736end
    18 end
Note: See TracChangeset for help on using the changeset viewer.