Changeset 19571


Ignore:
Timestamp:
09/21/15 13:50:48 (10 years ago)
Author:
Mathieu Morlighem
Message:

CHG: new version of export_fig

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

Legend:

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

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

    r18904 r19571  
    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');
     
    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 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 ([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/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 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
  • TabularUnified issm/trunk-jpl/externalpackages/export_fig/append_pdfs.m

    r18904 r19571  
    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);
  • TabularUnified issm/trunk-jpl/externalpackages/export_fig/copyfig.m

    r18904 r19571  
     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
  • TabularUnified issm/trunk-jpl/externalpackages/export_fig/crop_borders.m

    r18904 r19571  
     1function [A, vA, vB, bb_rel] = crop_borders(A, bcol, padding)
    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
    911%
    1012%OUT:
    1113%   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),:,:).
     14%   vA     - coordinates in A that contain the cropped image
     15%   vB     - coordinates in B where the cropped version of A is placed
     16%   bb_rel - relative bounding box (used for eps-cropping)
    1417
    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;
     18% 06/03/15: Improved image cropping thanks to Oscar Hartogensis
     19% 08/06/15: Fixed issue #76: case of transparent figure bgcolor
     20
     21    if nargin < 3
     22        padding = 0;
     23    end
     24    [h, w, c, n] = size(A);
     25    if isempty(bcol)  % case of transparent bgcolor
     26        bcol = A(ceil(end/2),1,:,1);
     27    end
     28    if isscalar(bcol)
     29        bcol = bcol(ones(c, 1));
     30    end
     31
     32    % Crop margin from left
     33    bail = false;
     34    for l = 1:w
     35        for a = 1:c
     36            if ~all(col(A(:,l,a,:)) == bcol(a))
     37                bail = true;
     38                break;
     39            end
     40        end
     41        if bail
    2842            break;
    2943        end
    3044    end
    31     if bail
    32         break;
    33     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;
     45
     46    % Crop margin from right
     47    bcol = A(ceil(end/2),w,:,1);
     48    bail = false;
     49    for r = w:-1:l
     50        for a = 1:c
     51            if ~all(col(A(:,r,a,:)) == bcol(a))
     52                bail = true;
     53                break;
     54            end
     55        end
     56        if bail
    4157            break;
    4258        end
    4359    end
    44     if bail
    45         break;
    46     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;
     60
     61    % Crop margin from top
     62    bcol = A(1,ceil(end/2),:,1);
     63    bail = false;
     64    for t = 1:h
     65        for a = 1:c
     66            if ~all(col(A(t,:,a,:)) == bcol(a))
     67                bail = true;
     68                break;
     69            end
     70        end
     71        if bail
    5472            break;
    5573        end
    5674    end
    57     if bail
    58         break;
    59     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;
     75
     76    % Crop margin from bottom
     77    bcol = A(h,ceil(end/2),:,1);
     78    bail = false;
     79    for b = h:-1:t
     80        for a = 1:c
     81            if ~all(col(A(b,:,a,:)) == bcol(a))
     82                bail = true;
     83                break;
     84            end
     85        end
     86        if bail
    6787            break;
    6888        end
    6989    end
    70     if bail
    71         break;
     90
     91    % Crop the background, leaving one boundary pixel to avoid bleeding on resize
     92    %v = [max(t-padding, 1) min(b+padding, h) max(l-padding, 1) min(r+padding, w)];
     93    %A = A(v(1):v(2),v(3):v(4),:,:);
     94    if padding == 0  % no padding
     95        padding = 1;
     96    elseif abs(padding) < 1  % pad value is a relative fraction of image size
     97        padding = sign(padding)*round(mean([b-t r-l])*abs(padding)); % ADJUST PADDING
     98    else  % pad value is in units of 1/72" points
     99        padding = round(padding);  % fix cases of non-integer pad value
    72100    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),:,:);
     101
     102    if padding > 0  % extra padding
     103        % Create an empty image, containing the background color, that has the
     104        % cropped image size plus the padded border
     105        B = repmat(bcol,(b-t)+1+padding*2,(r-l)+1+padding*2);
     106        % vA - coordinates in A that contain the cropped image
     107        vA = [t b l r];
     108        % vB - coordinates in B where the cropped version of A will be placed
     109        vB = [padding+1, (b-t)+1+padding, padding+1, (r-l)+1+padding];
     110        % Place the original image in the empty image
     111        B(vB(1):vB(2), vB(3):vB(4), :) = A(vA(1):vA(2), vA(3):vA(4), :);
     112        A = B;
     113    else  % extra cropping
     114        vA = [t-padding b+padding l-padding r+padding];
     115        A = A(vA(1):vA(2), vA(3):vA(4), :);
     116        vB = [NaN NaN NaN NaN];
     117    end
     118
     119    % For EPS cropping, determine the relative BoundingBox - bb_rel
     120    bb_rel = [l-1 h-b-1 r+1 h-t+1]./[w h w h];
    77121end
    78122
    79123function A = col(A)
    80 A = A(:);
     124    A = A(:);
    81125end
  • TabularUnified issm/trunk-jpl/externalpackages/export_fig/eps2pdf.m

    r18904 r19571  
     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
    4656
    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"'];
     57    % Intialise the options string for ghostscript
     58    options = ['-q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -sOutputFile="' dest '"'];
     59    % Set crop option
     60    if nargin < 3 || crop
     61        options = [options ' -dEPSCrop'];
     62    end
     63    % Set the font path
     64    fp = font_path();
     65    if ~isempty(fp)
     66        options = [options ' -sFONTPATH="' fp '"'];
     67    end
     68    % Set the grayscale option
     69    if nargin > 4 && gray
     70        options = [options ' -sColorConversionStrategy=Gray -dProcessColorModel=/DeviceGray'];
     71    end
     72    % Set the bitmap quality
     73    if nargin > 5 && ~isempty(quality)
     74        options = [options ' -dAutoFilterColorImages=false -dAutoFilterGrayImages=false'];
     75        if quality > 100
     76            options = [options ' -dColorImageFilter=/FlateEncode -dGrayImageFilter=/FlateEncode -c ".setpdfwrite << /ColorImageDownsampleThreshold 10 /GrayImageDownsampleThreshold 10 >> setdistillerparams"'];
     77        else
     78            options = [options ' -dColorImageFilter=/DCTEncode -dGrayImageFilter=/DCTEncode'];
     79            v = 1 + (quality < 80);
     80            quality = 1 - quality / 100;
     81            s = sprintf('<< /QFactor %.2f /Blend 1 /HSample [%d 1 1 %d] /VSample [%d 1 1 %d] >>', quality, v, v, v, v);
     82            options = sprintf('%s -c ".setpdfwrite << /ColorImageDict %s /GrayImageDict %s >> setdistillerparams"', options, s, s);
     83        end
     84    end
     85    % Enable users to specify optional ghostscript options (issue #36)
     86    if nargin > 6 && ~isempty(gs_options)
     87        if iscell(gs_options)
     88            gs_options = sprintf(' %s',gs_options{:});
     89        elseif ~ischar(gs_options)
     90            error('gs_options input argument must be a string or cell-array of strings');
     91        else
     92            gs_options = [' ' gs_options];
     93        end
     94        options = [options gs_options];
     95    end
     96    % Check if the output file exists
     97    if nargin > 3 && append && exist(dest, 'file') == 2
     98        % File exists - append current figure to the end
     99        tmp_nam = tempname;
     100        try
     101            % Ensure that the temp dir is writable (Javier Paredes 26/2/15)
     102            fid = fopen(tmp_nam,'w');
     103            fwrite(fid,1);
     104            fclose(fid);
     105            delete(tmp_nam);
     106        catch
     107            % Temp dir is not writable, so use the dest folder
     108            [dummy,fname,fext] = fileparts(tmp_nam); %#ok<ASGLU>
     109            fpath = fileparts(dest);
     110            tmp_nam = fullfile(fpath,[fname fext]);
     111        end
     112        % Copy the file
     113        copyfile(dest, tmp_nam);
     114        % Add the output file names
     115        options = [options ' -f "' tmp_nam '" "' source '"'];
     116        try
     117            % Convert to pdf using ghostscript
     118            [status, message] = ghostscript(options);
     119        catch me
     120            % Delete the intermediate file
     121            delete(tmp_nam);
     122            rethrow(me);
     123        end
     124        % Delete the intermediate file
     125        delete(tmp_nam);
    68126    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
     127        % File doesn't exist or should be over-written
     128        % Add the output file names
     129        options = [options ' -f "' source '"'];
    85130        % Convert to pdf using ghostscript
    86131        [status, message] = ghostscript(options);
    87     catch me
    88         % Delete the intermediate file
    89         delete(tmp_nam);
    90         rethrow(me);
    91132    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);
     133    % Check for error
     134    if status
     135        % Retry without the -sFONTPATH= option (this might solve some GS
     136        % /findfont errors according to James Rankin, FEX Comment 23/01/15)
     137        orig_options = options;
     138        if ~isempty(fp)
     139            options = regexprep(options, ' -sFONTPATH=[^ ]+ ',' ');
     140            status = ghostscript(options);
     141            if ~status, return; end  % hurray! (no error)
     142        end
     143        % Report error
     144        if isempty(message)
     145            error('Unable to generate pdf. Check destination directory is writable.');
     146        else
     147            fprintf(2, 'Ghostscript error: perhaps %s is open by another application\n', dest);
     148            if ~isempty(gs_options)
     149                fprintf(2, '  or maybe the%s option(s) are not accepted by your GS version\n', gs_options);
     150            end
     151            fprintf(2, 'Ghostscript options: %s\n\n', orig_options);
     152            error(message);
     153        end
    108154    end
    109 end
    110155end
    111156
    112157% Function to return (and create, where necessary) the font path
    113158function fp = font_path()
    114 fp = user_string('gs_font_path');
    115 if ~isempty(fp)
    116     return
     159    fp = user_string('gs_font_path');
     160    if ~isempty(fp)
     161        return
     162    end
     163    % Create the path
     164    % Start with the default path
     165    fp = getenv('GS_FONTPATH');
     166    % Add on the typical directories for a given OS
     167    if ispc
     168        if ~isempty(fp)
     169            fp = [fp ';'];
     170        end
     171        fp = [fp getenv('WINDIR') filesep 'Fonts'];
     172    else
     173        if ~isempty(fp)
     174            fp = [fp ':'];
     175        end
     176        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'];
     177    end
     178    user_string('gs_font_path', fp);
    117179end
    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
  • TabularUnified issm/trunk-jpl/externalpackages/export_fig/export_fig.m

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

    r18904 r19571  
    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
  • TabularUnified issm/trunk-jpl/externalpackages/export_fig/ghostscript.m

    r18904 r19571  
     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%}
    2344
    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));
     45    try
     46        % Call ghostscript
     47        [varargout{1:nargout}] = system([gs_command(gs_path()) cmd]);
     48    catch err
     49        % Display possible workarounds for Ghostscript croaks
     50        url1 = 'https://github.com/altmany/export_fig/issues/12#issuecomment-61467998';  % issue #12
     51        url2 = 'https://github.com/altmany/export_fig/issues/20#issuecomment-63826270';  % issue #20
     52        hg2_str = ''; if using_hg2, hg2_str = ' or Matlab R2014a'; end
     53        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);
     54        if using_hg2
     55            fprintf(2, '(GS 9.10)\n * <a href="%s">%s</a> (R2014a)',url2,url2);
     56        end
     57        fprintf('\n\n');
     58        if ismac || isunix
     59            url3 = 'https://github.com/altmany/export_fig/issues/27';  % issue #27
     60            fprintf(2, 'Alternatively, this may possibly be due to a font path issue:\n * <a href="%s">%s</a>\n\n',url3,url3);
     61            % issue #20
     62            fpath = which(mfilename);
     63            if isempty(fpath), fpath = [mfilename('fullpath') '.m']; end
     64            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);
     65        end
     66        rethrow(err);
     67    end
    5268end
    5369
    5470function 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_)
     71    % Return a valid path
     72    % Start with the currently set path
     73    path_ = user_string('ghostscript');
     74    % Check the path works
     75    if check_gs_path(path_)
    7176        return
    7277    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
     78    % Check whether the binary is on the path
     79    if ispc
     80        bin = {'gswin32c.exe', 'gswin64c.exe', 'gs'};
     81    else
     82        bin = {'gs'};
     83    end
     84    for a = 1:numel(bin)
     85        path_ = bin{a};
     86        if check_store_gs_path(path_)
     87            return
     88        end
     89    end
     90    % Search the obvious places
     91    if ispc
     92        default_location = 'C:\Program Files\gs\';
    8093        dir_list = dir(default_location);
     94        if isempty(dir_list)
     95            default_location = 'C:\Program Files (x86)\gs\'; % Possible location on 64-bit systems
     96            dir_list = dir(default_location);
     97        end
     98        executable = {'\bin\gswin32c.exe', '\bin\gswin64c.exe'};
     99        ver_num = 0;
     100        % If there are multiple versions, use the newest
     101        for a = 1:numel(dir_list)
     102            ver_num2 = sscanf(dir_list(a).name, 'gs%g');
     103            if ~isempty(ver_num2) && ver_num2 > ver_num
     104                for b = 1:numel(executable)
     105                    path2 = [default_location dir_list(a).name executable{b}];
     106                    if exist(path2, 'file') == 2
     107                        path_ = path2;
     108                        ver_num = ver_num2;
     109                    end
     110                end
     111            end
     112        end
     113        if check_store_gs_path(path_)
     114            return
     115        end
     116    else
     117        executable = {'/usr/bin/gs', '/usr/local/bin/gs'};
     118        for a = 1:numel(executable)
     119            path_ = executable{a};
     120            if check_store_gs_path(path_)
     121                return
     122            end
     123        end
    81124    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;
     125    % Ask the user to enter the path
     126    while true
     127        if strncmp(computer, 'MAC', 3) % Is a Mac
     128            % Give separate warning as the uigetdir dialogue box doesn't have a
     129            % title
     130            uiwait(warndlg('Ghostscript not found. Please locate the program.'))
     131        end
     132        base = uigetdir('/', 'Ghostcript not found. Please locate the program.');
     133        if isequal(base, 0)
     134            % User hit cancel or closed window
     135            break;
     136        end
     137        base = [base filesep]; %#ok<AGROW>
     138        bin_dir = {'', ['bin' filesep], ['lib' filesep]};
     139        for a = 1:numel(bin_dir)
     140            for b = 1:numel(bin)
     141                path_ = [base bin_dir{a} bin{b}];
     142                if exist(path_, 'file') == 2
     143                    if check_store_gs_path(path_)
     144                        return
     145                    end
    93146                end
    94147            end
    95148        end
    96149    end
    97     if check_store_gs_path(path_)
    98         return
    99     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?');
     150    error('Ghostscript not found. Have you installed it from www.ghostscript.com?');
    135151end
    136152
    137153function 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
     154    % Check the path is valid
     155    good = check_gs_path(path_);
     156    if ~good
     157        return
     158    end
     159    % Update the current default path to the path found
     160    if ~user_string('ghostscript', path_)
     161        filename = fullfile(fileparts(which('user_string.m')), '.ignore', 'ghostscript.txt');
     162        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_);
     163        return
     164    end
    148165end
    149166
    150167function 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
     168    persistent isOk
     169    if isempty(path_)
     170        isOk = false;
     171    elseif ~isequal(isOk,true)
     172        % Check whether the path is valid
     173        [status, message] = system([gs_command(path_) '-h']); %#ok<ASGLU>
     174        isOk = status == 0;
     175    end
     176    good = isOk;
    155177end
    156 [good, message] = system(sprintf('%s"%s" -h', shell_cmd, path_));
    157 good = good == 0;
     178
     179function cmd = gs_command(path_)
     180    % Initialize any required system calls before calling ghostscript
     181    % TODO: in Unix/Mac, find a way to determine whether to use "export" (bash) or "setenv" (csh/tcsh)
     182    shell_cmd = '';
     183    if isunix
     184        shell_cmd = 'export LD_LIBRARY_PATH=""; '; % Avoids an error on Linux with GS 9.07
     185    end
     186    if ismac
     187        shell_cmd = 'export DYLD_LIBRARY_PATH=""; ';  % Avoids an error on Mac with GS 9.07
     188    end
     189    % Construct the command string
     190    cmd = sprintf('%s"%s" ', shell_cmd, path_);
    158191end
  • TabularUnified issm/trunk-jpl/externalpackages/export_fig/isolate_axes.m

    r18904 r19571  
     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
  • TabularUnified issm/trunk-jpl/externalpackages/export_fig/pdftops.m

    r18904 r19571  
    2929% under linux.
    3030% 23/01/2014 - Add full path to pdftops.txt in warning.
     31% 27/05/2015 - Fixed alert in case of missing pdftops; fixed code indentation
    3132
    32 % Call pdftops
    33 [varargout{1:nargout}] = system(sprintf('"%s" %s', xpdf_path, cmd));
     33    % Call pdftops
     34    [varargout{1:nargout}] = system(sprintf('"%s" %s', xpdf_path, cmd));
    3435end
    3536
    3637function 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/.'))
     38    % Return a valid path
     39    % Start with the currently set path
     40    path_ = user_string('pdftops');
     41    % Check the path works
     42    if check_xpdf_path(path_)
     43        return
    6944    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;
     45    % Check whether the binary is on the path
     46    if ispc
     47        bin = 'pdftops.exe';
     48    else
     49        bin = 'pdftops';
    7450    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;
    81         end
     51    if check_store_xpdf_path(bin)
     52        path_ = bin;
     53        return
     54    end
     55    % Search the obvious places
     56    if ispc
     57        path_ = 'C:\Program Files\xpdf\pdftops.exe';
     58    else
     59        path_ = '/usr/local/bin/pdftops';
    8260    end
    8361    if check_store_xpdf_path(path_)
    8462        return
    8563    end
    86 end
    87 error('pdftops executable not found.');
     64    % Ask the user to enter the path
     65    while 1
     66        errMsg = 'Pdftops not found. Please locate the program, or install xpdf-tools from ';
     67        url = 'http://foolabs.com/xpdf';
     68        fprintf(2, '%s\n', [errMsg '<a href="matlab:web(''-browser'',''' url ''');">' url '</a>']);
     69        errMsg = [errMsg url]; %#ok<AGROW>
     70        if strncmp(computer,'MAC',3) % Is a Mac
     71            % Give separate warning as the MacOS uigetdir dialogue box doesn't have a title
     72            uiwait(warndlg(errMsg))
     73        end
     74        base = uigetdir('/', errMsg);
     75        if isequal(base, 0)
     76            % User hit cancel or closed window
     77            break;
     78        end
     79        base = [base filesep]; %#ok<AGROW>
     80        bin_dir = {'', ['bin' filesep], ['lib' filesep]};
     81        for a = 1:numel(bin_dir)
     82            path_ = [base bin_dir{a} bin];
     83            if exist(path_, 'file') == 2
     84                break;
     85            end
     86        end
     87        if check_store_xpdf_path(path_)
     88            return
     89        end
     90    end
     91    error('pdftops executable not found.');
    8892end
    8993
    9094function 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
     95    % Check the path is valid
     96    good = check_xpdf_path(path_);
     97    if ~good
     98        return
     99    end
     100    % Update the current default path to the path found
     101    if ~user_string('pdftops', path_)
     102        warning('Path to pdftops executable could not be saved. Enter it manually in %s.', fullfile(fileparts(which('user_string.m')), '.ignore', 'pdftops.txt'));
     103        return
     104    end
    101105end
    102106
    103107function 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'));
     108    % Check the path is valid
     109    [good, message] = system(sprintf('"%s" -h', path_)); %#ok<ASGLU>
     110    % system returns good = 1 even when the command runs
     111    % Look for something distinct in the help text
     112    good = ~isempty(strfind(message, 'PostScript'));
    109113end
  • TabularUnified issm/trunk-jpl/externalpackages/export_fig/print2array.m

    r18904 r19571  
     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
  • TabularUnified issm/trunk-jpl/externalpackages/export_fig/print2eps.m

    r18904 r19571  
     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 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       - Crop amount. Deafult: 0
     27%       fontswap   - Whether to swap non-default fonts in figure. Default: true
     28%   print_options - Additional parameter strings to be passed to the print command
     29
     30%{
     31% Copyright (C) Oliver Woodford 2008-2014, Yair Altman 2015-
    2832
    2933% The idea of editing the EPS file to change line styles comes from Jiro
     
    3135% The idea of changing dash length with line width came from comments on
    3236% 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.
     37%}
     38%{
     39% 14/11/11: Fix a MATLAB bug rendering black or white text incorrectly.
     40%           Thanks to Mathieu Morlighem for reporting the issue and
     41%           obtaining a fix from TMW.
    3742% 08/12/11: Added ability to correct fonts. Several people have requested
    3843%           this at one time or another, and also pointed me to printeps
     
    5863% 13/08/13: Fix MATLAB feature of not exporting white lines correctly.
    5964%           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
     65% 24/02/15: Fix for Matlab R2014b bug (issue #31): LineWidths<0.75 are not
     66%           set in the EPS (default line width is used)
     67% 25/02/15: Fixed issue #32: BoundingBox problem caused uncropped EPS/PDF files
     68% 05/03/15: Fixed issue #43: Inability to perform EPS file post-processing
     69% 06/03/15: Improved image padding & cropping thanks to Oscar Hartogensis
     70% 21/03/15: Fixed edge-case of missing handles having a 'FontName' property
     71% 26/03/15: Attempt to fix issue #45: white lines in subplots do not print correctly
     72% 27/03/15: Attempt to fix issue #44: white artifact lines appearing in patch exports
     73% 30/03/15: Fixed issue #52: improved performance on HG2 (R2014b+)
     74% 09/04/15: Comment blocks consolidation and minor code cleanup (no real code change)
     75% 12/04/15: Fixed issue #56: bad cropping
     76% 14/04/15: Workaround for issue #45: lines in image subplots are exported in invalid color
     77% 07/07/15: Added option to avoid font-swapping in EPS/PDF
     78% 07/07/15: Fixed issue #83: use numeric handles in HG1
     79% 22/07/15: Fixed issue #91 (thanks to Carlos Moffat)
     80%}
     81
     82    options = {'-loose'};
     83    if nargin > 3
     84        options = [options varargin];
     85    elseif nargin < 3
     86        export_options = 0;
     87        if nargin < 2
     88            fig = gcf();
     89        end
     90    end
     91
     92    % Retrieve padding, crop & font-swap values
     93    if numel(export_options) > 2  % font-swapping
     94        fontswap = export_options(3);
     95    else
     96        fontswap = true;
     97    end
     98    if numel(export_options) > 1  % cropping
     99        bb_crop = export_options(2);
     100    else
     101        bb_crop = 0;  % scalar value, so use default bb_crop value of 0
     102    end
     103    if numel(export_options) > 0  % padding
     104        bb_padding = export_options(1);
     105    else
     106        bb_padding = 0;
     107    end
     108
     109    % Construct the filename
     110    if numel(name) < 5 || ~strcmpi(name(end-3:end), '.eps')
     111        name = [name '.eps']; % Add the missing extension
     112    end
     113
     114    % Set paper size
     115    old_pos_mode = get(fig, 'PaperPositionMode');
     116    old_orientation = get(fig, 'PaperOrientation');
     117    set(fig, 'PaperPositionMode', 'auto', 'PaperOrientation', 'portrait');
     118
     119    % Find all the used fonts in the figure
     120    font_handles = findall(fig, '-property', 'FontName');
     121    fonts = get(font_handles, 'FontName');
     122    if isempty(fonts)
     123        fonts = {};
     124    elseif ~iscell(fonts)
     125        fonts = {fonts};
     126    end
     127
     128    % Map supported font aliases onto the correct name
     129    fontsl = lower(fonts);
     130    for a = 1:numel(fonts)
     131        f = fontsl{a};
     132        f(f==' ') = [];
     133        switch f
     134            case {'times', 'timesnewroman', 'times-roman'}
     135                fontsl{a} = 'times-roman';
     136            case {'arial', 'helvetica'}
     137                fontsl{a} = 'helvetica';
     138            case {'newcenturyschoolbook', 'newcenturyschlbk'}
     139                fontsl{a} = 'newcenturyschlbk';
     140            otherwise
     141        end
     142    end
     143    fontslu = unique(fontsl);
     144
     145    % Determine the font swap table
     146    if fontswap
     147        matlab_fonts = {'Helvetica', 'Times-Roman', 'Palatino', 'Bookman', 'Helvetica-Narrow', 'Symbol', ...
     148                        'AvantGarde', 'NewCenturySchlbk', 'Courier', 'ZapfChancery', 'ZapfDingbats'};
     149        matlab_fontsl = lower(matlab_fonts);
     150        require_swap = find(~ismember(fontslu, matlab_fontsl));
     151        unused_fonts = find(~ismember(matlab_fontsl, fontslu));
     152        font_swap = cell(3, min(numel(require_swap), numel(unused_fonts)));
     153        fonts_new = fonts;
     154        for a = 1:size(font_swap, 2)
     155            font_swap{1,a} = find(strcmp(fontslu{require_swap(a)}, fontsl));
     156            font_swap{2,a} = matlab_fonts{unused_fonts(a)};
     157            font_swap{3,a} = fonts{font_swap{1,a}(1)};
     158            fonts_new(font_swap{1,a}) = font_swap(2,a);
     159        end
     160    else
     161        font_swap = [];
     162    end
     163
     164    % Swap the fonts
     165    if ~isempty(font_swap)
     166        fonts_size = get(font_handles, 'FontSize');
     167        if iscell(fonts_size)
     168            fonts_size = cell2mat(fonts_size);
     169        end
     170        M = false(size(font_handles));
     171
     172        % Loop because some changes may not stick first time, due to listeners
     173        c = 0;
     174        update = zeros(1000, 1);
     175        for b = 1:10 % Limit number of loops to avoid infinite loop case
     176            for a = 1:numel(M)
     177                M(a) = ~isequal(get(font_handles(a), 'FontName'), fonts_new{a}) || ~isequal(get(font_handles(a), 'FontSize'), fonts_size(a));
     178                if M(a)
     179                    set(font_handles(a), 'FontName', fonts_new{a}, 'FontSize', fonts_size(a));
     180                    c = c + 1;
     181                    update(c) = a;
     182                end
     183            end
     184            if ~any(M)
     185                break;
     186            end
     187        end
     188
     189        % Compute the order to revert fonts later, without the need of a loop
     190        [update, M] = unique(update(1:c));
     191        [M, M] = sort(M);
     192        update = reshape(update(M), 1, []);
     193    end
     194
     195    % MATLAB bug fix - black and white text can come out inverted sometimes
     196    % Find the white and black text
     197    black_text_handles = findall(fig, 'Type', 'text', 'Color', [0 0 0]);
     198    white_text_handles = findall(fig, 'Type', 'text', 'Color', [1 1 1]);
     199    % Set the font colors slightly off their correct values
     200    set(black_text_handles, 'Color', [0 0 0] + eps);
     201    set(white_text_handles, 'Color', [1 1 1] - eps);
     202
     203    % MATLAB bug fix - white lines can come out funny sometimes
     204    % Find the white lines
     205    white_line_handles = findall(fig, 'Type', 'line', 'Color', [1 1 1]);
     206    % Set the line color slightly off white
     207    set(white_line_handles, 'Color', [1 1 1] - 0.00001);
     208
     209    % Workaround for issue #45: lines in image subplots are exported in invalid color
     210    % In this case the -depsc driver solves the problem, but then all the other workarounds
     211    % below (for all the other issues) will fail, so it's better to let the user decide by
     212    % just issuing a warning and accepting the '-depsc' input parameter
     213    epsLevel2 = ~any(strcmpi(options,'-depsc'));
     214    if epsLevel2
     215        % Use -depsc2 (EPS color level-2) if -depsc (EPS color level-3) was not specifically requested
     216        options{end+1} = '-depsc2';
     217        % Issue a warning if multiple images & lines were found in the figure, and HG1 with painters renderer is used
     218        isPainters = any(strcmpi(options,'-painters'));
     219        if isPainters && ~using_hg2 && numel(findall(fig,'Type','image'))>1 && ~isempty(findall(fig,'Type','line'))
     220            warning('YMA:export_fig:issue45', ...
     221                    ['Multiple images & lines detected. In such cases, the lines might \n' ...
     222                     'appear with an invalid color due to an internal MATLAB bug (fixed in R2014b). \n' ...
     223                     'Possible workaround: add a ''-depsc'' or ''-opengl'' parameter to the export_fig command.']);
     224        end
     225    end
     226
     227    % Fix issue #83: use numeric handles in HG1
     228    if ~using_hg2(fig),  fig = double(fig);  end
     229
     230    % Print to eps file
     231    print(fig, options{:}, name);
     232
     233    % Do post-processing on the eps file
     234    try
     235        % Read the EPS file into memory
     236        fstrm = read_write_entire_textfile(name);
     237    catch
     238        fstrm = '';
     239    end
     240
     241    % Fix for Matlab R2014b bug (issue #31): LineWidths<0.75 are not set in the EPS (default line width is used)
     242    try
     243        if ~isempty(fstrm) && using_hg2(fig)
     244            % Convert miter joins to line joins
     245            %fstrm = regexprep(fstrm, '\n10.0 ML\n', '\n1 LJ\n');
     246            % This is faster (the original regexprep could take many seconds when the axes contains many lines):
     247            fstrm = strrep(fstrm, sprintf('\n10.0 ML\n'), sprintf('\n1 LJ\n'));
     248
     249            % 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)
     250            %   hAxes=gca; hAxes.YGridHandle.LineWidth, hAxes.YRuler.Axle.LineWidth
     251            %fstrm = regexprep(fstrm, '(GC\n2 setlinecap\n1 LJ)\nN', '$1\n0.667 LW\nN');
     252            % This is faster:
     253            fstrm = strrep(fstrm, sprintf('GC\n2 setlinecap\n1 LJ\nN'), sprintf('GC\n2 setlinecap\n1 LJ\n0.667 LW\nN'));
     254
     255            % This is more accurate but *MUCH* slower (issue #52)
     256            %{
     257            % Modify all thin lines in the figure to have 10x LineWidths
     258            hLines = findall(fig,'Type','line');
     259            hThinLines = [];
     260            for lineIdx = 1 : numel(hLines)
     261                thisLine = hLines(lineIdx);
     262                if thisLine.LineWidth < 0.75 && strcmpi(thisLine.Visible,'on')
     263                    hThinLines(end+1) = thisLine; %#ok<AGROW>
     264                    thisLine.LineWidth = thisLine.LineWidth * 10;
     265                end
     266            end
     267
     268            % If any thin lines were found
     269            if ~isempty(hThinLines)
     270                % Prepare an EPS with large-enough line widths
     271                print(fig, options{:}, name);
     272                % Restore the original LineWidths in the figure
     273                for lineIdx = 1 : numel(hThinLines)
     274                    thisLine = handle(hThinLines(lineIdx));
     275                    thisLine.LineWidth = thisLine.LineWidth / 10;
     276                end
     277
     278                % Compare the original and the new EPS files and correct the original stream's LineWidths
     279                fstrm_new = read_write_entire_textfile(name);
     280                idx = 500;  % skip heading with its possibly-different timestamp
     281                markerStr = sprintf('10.0 ML\nN');
     282                markerLen = length(markerStr);
     283                while ~isempty(idx) && idx < length(fstrm)
     284                    lastIdx = min(length(fstrm), length(fstrm_new));
     285                    delta = fstrm(idx+1:lastIdx) - fstrm_new(idx+1:lastIdx);
     286                    idx = idx + find(delta,1);
     287                    if ~isempty(idx) && ...
     288                            isequal(fstrm(idx-markerLen+1:idx), markerStr) && ...
     289                            ~isempty(regexp(fstrm_new(idx-markerLen+1:idx+12),'10.0 ML\n[\d\.]+ LW\nN')) %#ok<RGXP1>
     290                        value = str2double(regexprep(fstrm_new(idx:idx+12),' .*',''));
     291                        if isnan(value), break; end  % something's wrong... - bail out
     292                        newStr = sprintf('%0.3f LW\n',value/10);
     293                        fstrm = [fstrm(1:idx-1) newStr fstrm(idx:end)];
     294                        idx = idx + 12;
     295                    else
     296                        break;
     297                    end
     298                end
     299            end
     300            %}
     301
     302            % This is much faster although less accurate: fix all non-gray lines to have a LineWidth of 0.75 (=1 LW)
     303            % Note: This will give incorrect LineWidth of 075 for lines having LineWidth<0.75, as well as for non-gray grid-lines (if present)
     304            %       However, in practice these edge-cases are very rare indeed, and the difference in LineWidth should not be noticeable
     305            %fstrm = regexprep(fstrm, '([CR]C\n2 setlinecap\n1 LJ)\nN', '$1\n1 LW\nN');
     306            % This is faster (the original regexprep could take many seconds when the axes contains many lines):
     307            fstrm = strrep(fstrm, sprintf('\n2 setlinecap\n1 LJ\nN'), sprintf('\n2 setlinecap\n1 LJ\n1 LW\nN'));
     308        end
     309    catch err
     310        fprintf(2, 'Error fixing LineWidths in EPS file: %s\n at %s:%d\n', err.message, err.stack(1).file, err.stack(1).line);
     311    end
     312
     313    % Reset the font and line colors
     314    set(black_text_handles, 'Color', [0 0 0]);
     315    set(white_text_handles, 'Color', [1 1 1]);
     316    set(white_line_handles, 'Color', [1 1 1]);
     317
     318    % Reset paper size
     319    set(fig, 'PaperPositionMode', old_pos_mode, 'PaperOrientation', old_orientation);
     320
     321    % Reset the font names in the figure
     322    if ~isempty(font_swap)
     323        for a = update
     324            set(font_handles(a), 'FontName', fonts{a}, 'FontSize', fonts_size(a));
     325        end
     326    end
     327
     328    % Bail out if EPS post-processing is not possible
     329    if isempty(fstrm)
     330        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.');
     331        return
     332    end
     333
     334    % Replace the font names
     335    if ~isempty(font_swap)
     336        for a = 1:size(font_swap, 2)
     337            %fstrm = regexprep(fstrm, [font_swap{1,a} '-?[a-zA-Z]*\>'], font_swap{3,a}(~isspace(font_swap{3,a})));
     338            fstrm = regexprep(fstrm, font_swap{2,a}, font_swap{3,a}(~isspace(font_swap{3,a})));
     339        end
     340    end
     341
     342    % Move the bounding box to the top of the file (HG2 only), or fix the line styles (HG1 only)
     343    if using_hg2(fig)
     344        % Move the bounding box to the top of the file (HG2 only)
     345        [s, e] = regexp(fstrm, '%%BoundingBox: [^%]*%%');
     346        if numel(s) == 2
     347            fstrm = fstrm([1:s(1)-1 s(2):e(2)-2 e(1)-1:s(2)-1 e(2)-1:end]);
     348        end
     349    else
     350        % Fix the line styles (HG1 only)
     351        fstrm = fix_lines(fstrm);
     352    end
     353
     354    % Apply the bounding box padding & cropping, replacing Matlab's print()'s bounding box
     355    if bb_crop
     356        % Calculate a new bounding box based on a bitmap print using crop_border.m
     357        % 1. Determine the Matlab BoundingBox and PageBoundingBox
     358        [s,e] = regexp(fstrm, '%%BoundingBox: [^%]*%%'); % location BB in eps file
     359        if numel(s)==2, s=s(2); e=e(2); end
     360        aa = fstrm(s+15:e-3); % dimensions bb - STEP1
     361        bb_matlab = cell2mat(textscan(aa,'%f32%f32%f32%f32'));  % dimensions bb - STEP2
     362
     363        [s,e] = regexp(fstrm, '%%PageBoundingBox: [^%]*%%'); % location bb in eps file
     364        if numel(s)==2, s=s(2); e=e(2); end
     365        aa = fstrm(s+19:e-3); % dimensions bb - STEP1
     366        pagebb_matlab = cell2mat(textscan(aa,'%f32%f32%f32%f32'));  % dimensions bb - STEP2
     367
     368        % 2. Create a bitmap image and use crop_borders to create the relative
     369        %    bb with respect to the PageBoundingBox
     370        [A, bcol] = print2array(fig, 1, '-opengl');
     371        [aa, aa, aa, bb_rel] = crop_borders(A, bcol, bb_padding);
     372
     373        % 3. Calculate the new Bounding Box
     374        pagew = pagebb_matlab(3)-pagebb_matlab(1);
     375        pageh = pagebb_matlab(4)-pagebb_matlab(2);
     376        %bb_new = [pagebb_matlab(1)+pagew*bb_rel(1) pagebb_matlab(2)+pageh*bb_rel(2) ...
     377        %          pagebb_matlab(1)+pagew*bb_rel(3) pagebb_matlab(2)+pageh*bb_rel(4)];
     378        bb_new = pagebb_matlab([1,2,1,2]) + [pagew,pageh,pagew,pageh].*bb_rel;  % clearer
     379        bb_offset = (bb_new-bb_matlab) + [-1,-1,1,1];  % 1px margin so that cropping is not TOO tight
     380
     381        % Apply the bounding box padding
     382        if bb_padding
     383            if abs(bb_padding)<1
     384                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
     385            end
     386            add_padding = @(n1, n2, n3, n4) sprintf(' %d', str2double({n1, n2, n3, n4}) + [-bb_padding -bb_padding bb_padding bb_padding] + bb_offset);
     387        else
     388            add_padding = @(n1, n2, n3, n4) sprintf(' %d', str2double({n1, n2, n3, n4}) + bb_offset); % fix small but noticeable bounding box shift
     389        end
     390        fstrm = regexprep(fstrm, '%%BoundingBox:[ ]+([-]?\d+)[ ]+([-]?\d+)[ ]+([-]?\d+)[ ]+([-]?\d+)', '%%BoundingBox:${add_padding($1, $2, $3, $4)}');
     391    end
     392
     393    % Fix issue #44: white artifact lines appearing in patch exports
     394    % Note: the problem is due to the fact that Matlab's print() function exports patches
     395    %       as a combination of filled triangles, and a white line appears where the triangles touch
     396    % In the workaround below, we will modify such dual-triangles into a filled rectangle.
     397    % We are careful to only modify regexps that exactly match specific patterns - it's better to not
     398    % correct some white-line artifacts than to change the geometry of a patch, or to corrupt the EPS.
     399    %   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'
     400    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');
     401    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');
     402    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');
     403    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');
     404
     405    % Write out the fixed eps file
     406    read_write_entire_textfile(name, fstrm);
    70407end
    71 % Construct the filename
    72 if numel(name) < 5 || ~strcmpi(name(end-3:end), '.eps')
    73     name = [name '.eps']; % Add the missing extension
    74 end
    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
  • TabularUnified issm/trunk-jpl/externalpackages/export_fig/user_string.m

    r18904 r19571  
     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
  • TabularUnified issm/trunk-jpl/externalpackages/export_fig/using_hg2.m

    r18904 r19571  
    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
    1214function tf = using_hg2(fig)
    13 try
    14     tf = ~graphicsversion(fig, 'handlegraphics');
    15 catch
    16     tf = false;
     15    persistent tf_cached
     16    if isempty(tf_cached)
     17        try
     18            if nargin < 1,  fig = figure('visible','off');  end
     19            oldWarn = warning('off','MATLAB:graphicsversion:GraphicsVersionRemoval');
     20            try
     21                % This generates a [supressed] warning in R2015b:
     22                tf = ~graphicsversion(fig, 'handlegraphics');
     23            catch
     24                tf = verLessThan('matlab','8.4');  % =R2014b
     25            end
     26            warning(oldWarn);
     27        catch
     28            tf = false;
     29        end
     30        if nargin < 1,  delete(fig);  end
     31        tf_cached = tf;
     32    else
     33        tf = tf_cached;
     34    end
    1735end
    18 end
Note: See TracChangeset for help on using the changeset viewer.