Skip to content

Commit 21beeea

Browse files
committed
(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
1 parent c6cdb2f commit 21beeea

File tree

2 files changed

+453
-260
lines changed

2 files changed

+453
-260
lines changed

export_fig.m

Lines changed: 112 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,14 @@
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+
% Optional suffix +-<value> adds tolerance to pixels color matching
121+
% for example: -transparent=g+-30 or -transparent=[1,.5,.2]+-0.1
122+
% Note: only supported by PNG,GIF,TIF formats.
117123
% -nocrop - option indicating that empty margins should not be cropped.
118124
% -c[<val>,<val>,<val>,<val>] - option indicating crop amounts. Must be
119125
% a 4-element vector of numeric values: [top,right,bottom,left]
@@ -399,6 +405,7 @@
399405
% 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)
400406
% 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)
401407
% 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
408+
% 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
402409
%}
403410

404411
if nargout
@@ -436,7 +443,7 @@
436443
[fig, options] = parse_args(nargout, fig, argNames, varargin{:});
437444

438445
% Check for newer version and exportgraphics/copygraphics compatibility
439-
currentVersion = 3.46;
446+
currentVersion = 3.47;
440447
if options.version % export_fig's version requested - return it and bail out
441448
imageData = currentVersion;
442449
return
@@ -675,9 +682,10 @@
675682

676683
% Initialize
677684
tmp_nam = '';
685+
isBgColor = false(0);
678686
exported_files = 0;
679687

680-
% Main processing
688+
% Main processing
681689
try
682690
oldWarn = warning;
683691

@@ -693,17 +701,21 @@
693701
error('export_fig:padding','For bitmap output (png,jpg,tif,bmp) the padding value (-p) must be between -1<p<1')
694702
end
695703
% Print large version to array
696-
[A, tcol, alpha] = getFigImage(fig, magnify, renderer, options, pixelpos);
704+
[A, bgcol, alpha] = getFigImage(fig, magnify, renderer, options, pixelpos);
697705
% Get the background colour
706+
if isempty(options.tcol), tcol = bgcol; else, tcol = options.tcol; end
698707
if options.transparent
699708
if (options.png || options.alpha || options.gif || options.tif)
700709
try %options.aa_factor < 4 % default, faster but lines are not anti-aliased
701710
% 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);
711+
A2 = single(A);
712+
tcol = single(tcol);
713+
ttol = single(options.ttol);
714+
isBgColor = abs(A2(:,:,1)-tcol(1)) <= ttol & ...
715+
abs(A2(:,:,2)-tcol(2)) <= ttol & ...
716+
abs(A2(:,:,3)-tcol(3)) <= ttol;
705717
% Set the bgcolor pixels to be fully-transparent
706-
A(repmat(isBgColor,[1,1,3])) = 254; %=off-white % TODO: more memory efficient without repmat
718+
%A(repmat(isBgColor,[1,1,3])) = 254; %=off-white % TODO: more memory efficient without repmat
707719
alpha(isBgColor) = 0;
708720
catch % older logic - much slower and causes figure flicker
709721
if true % to fold the code below...
@@ -805,7 +817,7 @@
805817
if options.crop
806818
%[alpha, v] = crop_borders(alpha, 0, 1, options.crop_amounts);
807819
%A = A(v(1):v(2),v(3):v(4),:);
808-
[A, vA, vB] = crop_borders(A, tcol, options.bb_padding, options.crop_amounts);
820+
[A, vA, vB] = crop_borders(A, bgcol, options.bb_padding, options.crop_amounts);
809821
if ~any(isnan(vB)) % positive padding
810822
sz = size(A); % Fix issue #308
811823
B = repmat(uint8(zeros(1,1,size(alpha,3))),sz([1,2])); % Fix issue #307 %=zeros(sz([1,2]),'uint8');
@@ -825,7 +837,9 @@
825837
end
826838
%}
827839
% Revert the figure properties back to their original values
828-
set(fig, 'Units',oldFigUnits, 'Position',pos, 'Color',tcol_orig);
840+
oldWarn = warning('off','MATLAB:Figure:SetPosition');
841+
try set(fig, 'Units',oldFigUnits, 'Position',pos, 'Color',tcol_orig); catch, end
842+
warning(oldWarn);
829843
% Check for greyscale images
830844
if options.colourspace == 2
831845
% Convert to greyscale
@@ -1694,6 +1708,8 @@ function notify(filename)
16941708
'crop', true, ...
16951709
'crop_amounts', nan(1,4), ... % auto-crop all 4 image sides
16961710
'transparent', false, ...
1711+
'tcol', [], ...
1712+
'ttol', 0, ...
16971713
'renderer', 0, ... % 0: default, 1: OpenGL, 2: ZBuffer, 3: Painters
16981714
'pdf', false, ...
16991715
'eps', false, ...
@@ -1775,12 +1791,51 @@ function notify(filename)
17751791
else %if ischar(thisArg) && ~isempty(thisArg)
17761792
if thisArg(1) == '-'
17771793
addToOptionsStr = true;
1794+
[thisArg,extra] = strtok(thisArg,'=');
17781795
switch lower(thisArg(2:end))
17791796
case 'nocrop'
17801797
options.crop = false;
17811798
options.crop_amounts = [0,0,0,0];
17821799
case {'trans', 'transparent'}
17831800
options.transparent = true;
1801+
extra = strtrim(lower(extra));
1802+
if length(extra) > 1
1803+
[extra,tol] = strtok(extra(2:end),'+-'); %discrad '='
1804+
if extra(1) >= 'a' && extra(1) <= 'z'
1805+
% convert predefined color => RGB
1806+
colIdx = find(extra(1)=='wrgbcmyk',1);
1807+
assert(~isempty(colIdx),'export_fig:invalid_tcol','Invalid transparent color ''%s'' specified',extra);
1808+
defaultColors = 255 * uint8([1,1,1; ... w
1809+
1,0,0; ... r
1810+
0,1,0; ... g
1811+
0,0,1; ... b
1812+
0,1,1; ... c
1813+
1,0,1; ... m
1814+
1,1,0; ... y
1815+
0,0,0]); % k
1816+
options.tcol = defaultColors(colIdx,:);
1817+
else
1818+
tcol = str2num(extra); %#ok<ST2NM>
1819+
assert(isequal(size(tcol),[1,3]),'export_fig:invalid_tcol','Invalid transparent color %s specified',extra);
1820+
if all(tcol <= 1) %fractional values
1821+
tcol = 255 * tcol; %[0-1] => [0-255]
1822+
end
1823+
options.tcol = uint8(tcol);
1824+
end
1825+
if length(tol) > 2
1826+
tol = tol(3:end); % discard '+-'
1827+
ttol = str2num(tol); %#ok<ST2NM>
1828+
assert(isscalar(ttol) && ttol>=0,'export_fig:invalid_ttol','Invalid transparent color tolerance %s specified',tol);
1829+
if ttol <= 1 %fractional value
1830+
ttol = 255 * ttol; %[0-1] => [0-255]
1831+
end
1832+
options.ttol = uint8(ttol);
1833+
elseif ~isempty(tol) % just '+-'
1834+
warning('export_fig:invalid_ttol','No transparent color tolerance specified - ignored');
1835+
end
1836+
elseif ~isempty(extra) % just '='
1837+
warning('export_fig:invalid_tcol','No transparent color specified - ignored');
1838+
end
17841839
case 'opengl'
17851840
options.renderer = 1;
17861841
case 'zbuffer'
@@ -1929,8 +1984,8 @@ function notify(filename)
19291984
error('export_fig:BadOptionValue','export_fig metadata must be a struct or cell-array of name-value pairs');
19301985
end
19311986
metadata = cellfun(@num2str,metadata(:)','uniform',0);
1932-
str = sprintf(' /%s (%s)', metadata{:});
1933-
options.gs_options{end+1} = ['-c "[' str ' /DOCINFO pdfmark"'];
1987+
extra = sprintf(' /%s (%s)', metadata{:});
1988+
options.gs_options{end+1} = ['-c "[' extra ' /DOCINFO pdfmark"'];
19341989
skipNext = 1;
19351990
otherwise
19361991
try
@@ -2098,6 +2153,11 @@ function notify(filename)
20982153
end
20992154
end
21002155

2156+
% transparent color cannot be specified for vector output
2157+
if ~isempty(options.tcol) && ~isbitmap(options)
2158+
error('export_fig:vector_tcol','Transparent color cannot be specified with non-bitmap outputs');
2159+
end
2160+
21012161
% Quick bail-out if no figure found
21022162
if isempty(fig), return; end
21032163

@@ -2232,6 +2292,7 @@ function notify(filename)
22322292
end
22332293
end
22342294
end
2295+
22352296
function options = setOptionsFormat(options, ext)
22362297
switch lower(ext(2:end))
22372298
case {'tif', 'tiff'}, options.tif = true;
@@ -2335,27 +2396,50 @@ function eps_remove_background(fname, count)
23352396
options.gif || options.im || options.alpha;
23362397
end
23372398

2338-
function [A, tcol, alpha] = getFigImage(fig, magnify, renderer, options, pos)
2399+
function [A, bgcol, alpha] = getFigImage(fig, magnify, renderer, options, pos)
23392400
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;
2401+
% Modify the figure's bgcolor to off-white
2402+
if isempty(options.tcol)
2403+
bgcol = uint8(254*[1,1,1]); %default bgcolor =off-white
2404+
2405+
% Determine off-white shade not already used in the fig - issue #398
2406+
A = getFigImage2(fig, magnify, renderer, options); % get RGB tripplets
2407+
A = unique(reshape(A,[],3),'rows'); % reshape [m,n,3] => [m*n,3]
2408+
A = sum(double(A).*(256.^[2,1,0]),2); % convert RGB tripplets => int
2409+
d = A(find(diff(A)>1,1,'last')+1) - 1; %=largest RGB value -1 (off-white)
2410+
if ~isempty(d)
2411+
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
2412+
end
2413+
2414+
% MATLAB "feature": figure size can change when changing color in -nodisplay mode
2415+
% Note: figure background is set to off-white, not 'w', to handle common white elements (issue #330)
2416+
set(fig, 'Color',double(bgcol)/255, 'Position',pos);
2417+
2418+
% repaint figure, otherwise Java screencapture will see black bgcolor
2419+
% Yair 19/12/21 - unnecessary: drawnow is called at top of print2array
2420+
%drawnow;
2421+
else
2422+
%bgcol = options.tcol;
2423+
end
23462424
end
2425+
23472426
% Print large version to array
2427+
[A, bgcol, alpha] = getFigImage2(fig, magnify, renderer, options);
2428+
2429+
% In transparent mode, set the bgcolor to white
2430+
if options.transparent
2431+
% Note: bgcol should already be [255,255,255] here, but just in case it's not...
2432+
%bgcol = uint8(254*[1,1,1]); %=off-white
2433+
end
2434+
end
2435+
2436+
function [A, bgcol, alpha] = getFigImage2(fig, magnify, renderer, options)
23482437
try
23492438
% The following code might cause out-of-memory errors
2350-
[A, tcol, alpha] = print2array(fig, magnify, renderer);
2439+
[A, bgcol, alpha] = print2array(fig, magnify, renderer);
23512440
catch
23522441
% 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
2442+
[A, bgcol, alpha] = print2array(fig, magnify/options.aa_factor, renderer, 'retry');
23592443
end
23602444
end
23612445

0 commit comments

Comments
 (0)