Skip to content

Commit 4594a4c

Browse files
committed
Update export_fig to v3.48
1 parent 83e23dd commit 4594a4c

File tree

2 files changed

+466
-260
lines changed

2 files changed

+466
-260
lines changed

export_fig/export_fig.m

Lines changed: 125 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
% export_fig ... -<format>
99
% export_fig ... -nocrop
1010
% export_fig ... -c[<val>,<val>,<val>,<val>]
11-
% export_fig ... -transparent
11+
% export_fig ... -transparent or: -transparent=<color>
1212
% export_fig ... -native
1313
% export_fig ... -m<val>
1414
% export_fig ... -r<val>
@@ -112,8 +112,17 @@
112112
% Multiple formats can be specified, without restriction.
113113
% For example: export_fig('-jpg', '-pdf', '-png', ...)
114114
% Note: '-tif','-tiff' are equivalent, and so are '-jpg','-jpeg'.
115-
% -transparent - option indicating that the figure background is to be made
116-
% transparent (PNG,PDF,TIF,EPS,EMF formats only). Implies -noinvert.
115+
% -transparent - indicates that figure background should be made transparent.
116+
% Note: PNG,GIF,TIF,PDF,EPS,EMF formats only. Implies -noinvert.
117+
% -transparent=<color> convert all pixels in the specified color (RGB tripplet
118+
% or a Matlab predefined color string e.g. 'r'). Usage examples:
119+
% -transparent=g or -transparent=[1,.5,.2] or -transparent=80,65,235
120+
% -transparent=<color>+-<value> adds optional tolerance to bgcolor matching.
121+
% For example: -transparent=g+-30 or -transparent=[1,.5,.2]+-0.1
122+
% <color> may be omitted, e.g. -transparent+-8 or -transparent=+-.03
123+
% Default tolerance is 0.1 (or 25 in [0,255] units), to reduce color
124+
% artifacts around letters and line edges. Note: transparent color
125+
% customization is only supported by PNG,GIF,TIF formats.
117126
% -nocrop - option indicating that empty margins should not be cropped.
118127
% -c[<val>,<val>,<val>,<val>] - option indicating crop amounts. Must be
119128
% a 4-element vector of numeric values: [top,right,bottom,left]
@@ -399,6 +408,8 @@
399408
% 21/02/24: (3.44) Fixed: text objects with normalized units were not exported in some cases (issue #373); added check for invalid ghostscript installation (issue #365)
400409
% 02/05/24: (3.45) Display the builtin error message when uifigure cannot be exported (issue #387); fixed contour labels with non-default FontName incorrectly exported as Courier (issue #388)
401410
% 09/05/24: (3.46) Added -xkcd option (thanks @slayton); added .fig input and output format (previously undocumented & buggy); redirect .tex output to matlab2tikz utility
411+
% 05/11/24: (3.47) Fixed -transparency in case the default bgcolor is already used in the figure (issue #398); enabled specifying non-default transparency color via -transparency parameter; suppress warnings about setting figure position; multiple -xkcd fixes
412+
% 06/03/25: (3.48) Fixed -transparency color artifacts, set default bgcolor tolerance of +-0.1 (issue #400)
402413
%}
403414

404415
if nargout
@@ -436,7 +447,7 @@
436447
[fig, options] = parse_args(nargout, fig, argNames, varargin{:});
437448

438449
% Check for newer version and exportgraphics/copygraphics compatibility
439-
currentVersion = 3.46;
450+
currentVersion = 3.48;
440451
if options.version % export_fig's version requested - return it and bail out
441452
imageData = currentVersion;
442453
return
@@ -675,9 +686,10 @@
675686

676687
% Initialize
677688
tmp_nam = '';
689+
isBgColor = false(0);
678690
exported_files = 0;
679691

680-
% Main processing
692+
% Main processing
681693
try
682694
oldWarn = warning;
683695

@@ -693,17 +705,21 @@
693705
error('export_fig:padding','For bitmap output (png,jpg,tif,bmp) the padding value (-p) must be between -1<p<1')
694706
end
695707
% Print large version to array
696-
[A, tcol, alpha] = getFigImage(fig, magnify, renderer, options, pixelpos);
708+
[A, bgcol, alpha] = getFigImage(fig, magnify, renderer, options, pixelpos);
697709
% Get the background colour
710+
if isempty(options.tcol), tcol = bgcol; else, tcol = options.tcol; end
698711
if options.transparent
699712
if (options.png || options.alpha || options.gif || options.tif)
700713
try %options.aa_factor < 4 % default, faster but lines are not anti-aliased
701714
% If all pixels are indicated as opaque (i.e. something went wrong with the Java screen-capture)
702-
isBgColor = A(:,:,1) == tcol(1) & ...
703-
A(:,:,2) == tcol(2) & ...
704-
A(:,:,3) == tcol(3);
715+
A2 = single(A);
716+
tcol = single(tcol);
717+
ttol = single(options.ttol);
718+
isBgColor = abs(A2(:,:,1)-tcol(1)) <= ttol & ...
719+
abs(A2(:,:,2)-tcol(2)) <= ttol & ...
720+
abs(A2(:,:,3)-tcol(3)) <= ttol;
705721
% Set the bgcolor pixels to be fully-transparent
706-
A(repmat(isBgColor,[1,1,3])) = 254; %=off-white % TODO: more memory efficient without repmat
722+
%A(repmat(isBgColor,[1,1,3])) = 254; %=off-white % TODO: more memory efficient without repmat
707723
alpha(isBgColor) = 0;
708724
catch % older logic - much slower and causes figure flicker
709725
if true % to fold the code below...
@@ -805,7 +821,7 @@
805821
if options.crop
806822
%[alpha, v] = crop_borders(alpha, 0, 1, options.crop_amounts);
807823
%A = A(v(1):v(2),v(3):v(4),:);
808-
[A, vA, vB] = crop_borders(A, tcol, options.bb_padding, options.crop_amounts);
824+
[A, vA, vB] = crop_borders(A, bgcol, options.bb_padding, options.crop_amounts);
809825
if ~any(isnan(vB)) % positive padding
810826
sz = size(A); % Fix issue #308
811827
B = repmat(uint8(zeros(1,1,size(alpha,3))),sz([1,2])); % Fix issue #307 %=zeros(sz([1,2]),'uint8');
@@ -825,7 +841,9 @@
825841
end
826842
%}
827843
% Revert the figure properties back to their original values
828-
set(fig, 'Units',oldFigUnits, 'Position',pos, 'Color',tcol_orig);
844+
oldWarn = warning('off','MATLAB:Figure:SetPosition');
845+
try set(fig, 'Units',oldFigUnits, 'Position',pos, 'Color',tcol_orig); catch, end
846+
warning(oldWarn);
829847
% Check for greyscale images
830848
if options.colourspace == 2
831849
% Convert to greyscale
@@ -1694,6 +1712,8 @@ function notify(filename)
16941712
'crop', true, ...
16951713
'crop_amounts', nan(1,4), ... % auto-crop all 4 image sides
16961714
'transparent', false, ...
1715+
'tcol', [], ...
1716+
'ttol', uint8(25), ... % in [0,255] RGB color units
16971717
'renderer', 0, ... % 0: default, 1: OpenGL, 2: ZBuffer, 3: Painters
16981718
'pdf', false, ...
16991719
'eps', false, ...
@@ -1775,12 +1795,58 @@ function notify(filename)
17751795
else %if ischar(thisArg) && ~isempty(thisArg)
17761796
if thisArg(1) == '-'
17771797
addToOptionsStr = true;
1798+
[thisArg,extra] = strtok(thisArg,{'=','+'});
17781799
switch lower(thisArg(2:end))
17791800
case 'nocrop'
17801801
options.crop = false;
17811802
options.crop_amounts = [0,0,0,0];
17821803
case {'trans', 'transparent'}
17831804
options.transparent = true;
1805+
extra = strtrim(lower(extra));
1806+
if length(extra) > 1
1807+
[extra,tol] = strtok(extra(2:end),'+-'); %discrad '='
1808+
if extra(1) >= 'a' && extra(1) <= 'z'
1809+
% convert predefined color => RGB
1810+
colIdx = find(extra(1)=='wrgbcmyk',1);
1811+
assert(~isempty(colIdx),'export_fig:invalid_tcol','Invalid transparent color ''%s'' specified',extra);
1812+
defaultColors = 255 * uint8([1,1,1; ... w
1813+
1,0,0; ... r
1814+
0,1,0; ... g
1815+
0,0,1; ... b
1816+
0,1,1; ... c
1817+
1,0,1; ... m
1818+
1,1,0; ... y
1819+
0,0,0]); % k
1820+
options.tcol = defaultColors(colIdx,:);
1821+
else
1822+
tcol = str2num(extra); %#ok<ST2NM>
1823+
if numel(tcol)==1 && isempty(tol)
1824+
if tcol <= 1 %fractional value
1825+
tcol = 255 * tcol; %[0-1] => [0-255]
1826+
end
1827+
options.ttol = uint8(tcol);
1828+
else
1829+
assert(isequal(size(tcol),[1,3]),'export_fig:invalid_tcol','Invalid transparent color %s specified',extra);
1830+
if all(tcol <= 1) %fractional values
1831+
tcol = 255 * tcol; %[0-1] => [0-255]
1832+
end
1833+
options.tcol = uint8(tcol);
1834+
end
1835+
end
1836+
if length(tol) > 2
1837+
tol = tol(3:end); % discard '+-'
1838+
ttol = str2num(tol); %#ok<ST2NM>
1839+
assert(isscalar(ttol) && ttol>=0,'export_fig:invalid_ttol','Invalid transparent color tolerance %s specified',tol);
1840+
if ttol <= 1 %fractional value
1841+
ttol = 255 * ttol; %[0-1] => [0-255]
1842+
end
1843+
options.ttol = uint8(ttol);
1844+
elseif ~isempty(tol) % just '+-'
1845+
warning('export_fig:invalid_ttol','No transparent color tolerance specified - ignored');
1846+
end
1847+
elseif ~isempty(extra) % just '='
1848+
warning('export_fig:invalid_tcol','No transparent color specified - ignored');
1849+
end
17841850
case 'opengl'
17851851
options.renderer = 1;
17861852
case 'zbuffer'
@@ -1929,8 +1995,8 @@ function notify(filename)
19291995
error('export_fig:BadOptionValue','export_fig metadata must be a struct or cell-array of name-value pairs');
19301996
end
19311997
metadata = cellfun(@num2str,metadata(:)','uniform',0);
1932-
str = sprintf(' /%s (%s)', metadata{:});
1933-
options.gs_options{end+1} = ['-c "[' str ' /DOCINFO pdfmark"'];
1998+
extra = sprintf(' /%s (%s)', metadata{:});
1999+
options.gs_options{end+1} = ['-c "[' extra ' /DOCINFO pdfmark"'];
19342000
skipNext = 1;
19352001
otherwise
19362002
try
@@ -2098,6 +2164,11 @@ function notify(filename)
20982164
end
20992165
end
21002166

2167+
% transparent color cannot be specified for vector output
2168+
if ~isempty(options.tcol) && ~isbitmap(options)
2169+
error('export_fig:vector_tcol','Transparent color cannot be specified with non-bitmap outputs');
2170+
end
2171+
21012172
% Quick bail-out if no figure found
21022173
if isempty(fig), return; end
21032174

@@ -2232,6 +2303,7 @@ function notify(filename)
22322303
end
22332304
end
22342305
end
2306+
22352307
function options = setOptionsFormat(options, ext)
22362308
switch lower(ext(2:end))
22372309
case {'tif', 'tiff'}, options.tif = true;
@@ -2335,27 +2407,52 @@ function eps_remove_background(fname, count)
23352407
options.gif || options.im || options.alpha;
23362408
end
23372409

2338-
function [A, tcol, alpha] = getFigImage(fig, magnify, renderer, options, pos)
2410+
function [A, bgcol, alpha] = getFigImage(fig, magnify, renderer, options, pos)
23392411
if options.transparent
2340-
% MATLAB "feature": figure size can change when changing color in -nodisplay mode
2341-
% Note: figure background is set to off-white, not 'w', to handle common white elements (issue #330)
2342-
set(fig, 'Color',254/255*[1,1,1], 'Position',pos);
2343-
% repaint figure, otherwise Java screencapture will see black bgcolor
2344-
% Yair 19/12/21 - unnecessary: drawnow is called at top of print2array
2345-
%drawnow;
2412+
% Modify the figure's bgcolor to off-white
2413+
if isempty(options.tcol)
2414+
bgcol = uint8([255,255,254]); %default bgcolor =off-white
2415+
white = uint8([255,255,255]);
2416+
2417+
% Determine off-white shade not already used in the fig - issue #398
2418+
A = getFigImage2(fig, magnify, renderer, options); % get RGB tripplets
2419+
A = reshape(A,[],3); % reshape [m,n,3] => [m*n,3]
2420+
A = unique([A; white], 'rows'); % add pure white %issue #400
2421+
A = sort(sum(double(A).*(256.^[2,1,0]),2)); % convert RGB tripplets => int
2422+
d = A(find(diff(A)>1,1,'last')+1) - 1; %=largest RGB value -1 (off-white)
2423+
if ~isempty(d)
2424+
n=2; while n>=0, p=256^n; bgcol(3-n)=floor(d/p); d=rem(d,p); n=n-1; end %int => RGB tripplet
2425+
end
2426+
2427+
% MATLAB "feature": figure size can change when changing color in -nodisplay mode
2428+
% Note: figure background is set to off-white, not 'w', to handle common white elements (issue #330)
2429+
set(fig, 'Color',double(bgcol)/255, 'Position',pos);
2430+
2431+
% repaint figure, otherwise Java screencapture will see black bgcolor
2432+
% Yair 19/12/21 - unnecessary: drawnow is called at top of print2array
2433+
%drawnow;
2434+
else
2435+
%bgcol = options.tcol;
2436+
end
23462437
end
2438+
23472439
% Print large version to array
2440+
[A, bgcol, alpha] = getFigImage2(fig, magnify, renderer, options);
2441+
2442+
% In transparent mode, set the bgcolor to white
2443+
if options.transparent
2444+
% Note: bgcol should already be [255,255,255] here, but just in case it's not...
2445+
%bgcol = uint8(254*[1,1,1]); %=off-white
2446+
end
2447+
end
2448+
2449+
function [A, bgcol, alpha] = getFigImage2(fig, magnify, renderer, options)
23482450
try
23492451
% The following code might cause out-of-memory errors
2350-
[A, tcol, alpha] = print2array(fig, magnify, renderer);
2452+
[A, bgcol, alpha] = print2array(fig, magnify, renderer);
23512453
catch
23522454
% This is more conservative in memory, but perhaps kills transparency(?)
2353-
[A, tcol, alpha] = print2array(fig, magnify/options.aa_factor, renderer, 'retry');
2354-
end
2355-
% In transparent mode, set the bgcolor to white
2356-
if options.transparent
2357-
% Note: tcol should already be [255,255,255] here, but just in case it's not...
2358-
tcol = uint8(254*[1,1,1]); %=off-white
2455+
[A, bgcol, alpha] = print2array(fig, magnify/options.aa_factor, renderer, 'retry');
23592456
end
23602457
end
23612458

0 commit comments

Comments
 (0)