|
8 | 8 | % export_fig ... -<format> |
9 | 9 | % export_fig ... -nocrop |
10 | 10 | % export_fig ... -c[<val>,<val>,<val>,<val>] |
11 | | -% export_fig ... -transparent |
| 11 | +% export_fig ... -transparent or: -transparent=<color> |
12 | 12 | % export_fig ... -native |
13 | 13 | % export_fig ... -m<val> |
14 | 14 | % export_fig ... -r<val> |
|
112 | 112 | % Multiple formats can be specified, without restriction. |
113 | 113 | % For example: export_fig('-jpg', '-pdf', '-png', ...) |
114 | 114 | % 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. |
117 | 126 | % -nocrop - option indicating that empty margins should not be cropped. |
118 | 127 | % -c[<val>,<val>,<val>,<val>] - option indicating crop amounts. Must be |
119 | 128 | % a 4-element vector of numeric values: [top,right,bottom,left] |
|
399 | 408 | % 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) |
400 | 409 | % 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) |
401 | 410 | % 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) |
402 | 413 | %} |
403 | 414 |
|
404 | 415 | if nargout |
|
436 | 447 | [fig, options] = parse_args(nargout, fig, argNames, varargin{:}); |
437 | 448 |
|
438 | 449 | % Check for newer version and exportgraphics/copygraphics compatibility |
439 | | - currentVersion = 3.46; |
| 450 | + currentVersion = 3.48; |
440 | 451 | if options.version % export_fig's version requested - return it and bail out |
441 | 452 | imageData = currentVersion; |
442 | 453 | return |
|
675 | 686 |
|
676 | 687 | % Initialize |
677 | 688 | tmp_nam = ''; |
| 689 | + isBgColor = false(0); |
678 | 690 | exported_files = 0; |
679 | 691 |
|
680 | | - % Main processing |
| 692 | + % Main processing |
681 | 693 | try |
682 | 694 | oldWarn = warning; |
683 | 695 |
|
|
693 | 705 | error('export_fig:padding','For bitmap output (png,jpg,tif,bmp) the padding value (-p) must be between -1<p<1') |
694 | 706 | end |
695 | 707 | % 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); |
697 | 709 | % Get the background colour |
| 710 | + if isempty(options.tcol), tcol = bgcol; else, tcol = options.tcol; end |
698 | 711 | if options.transparent |
699 | 712 | if (options.png || options.alpha || options.gif || options.tif) |
700 | 713 | try %options.aa_factor < 4 % default, faster but lines are not anti-aliased |
701 | 714 | % 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; |
705 | 721 | % 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 |
707 | 723 | alpha(isBgColor) = 0; |
708 | 724 | catch % older logic - much slower and causes figure flicker |
709 | 725 | if true % to fold the code below... |
|
805 | 821 | if options.crop |
806 | 822 | %[alpha, v] = crop_borders(alpha, 0, 1, options.crop_amounts); |
807 | 823 | %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); |
809 | 825 | if ~any(isnan(vB)) % positive padding |
810 | 826 | sz = size(A); % Fix issue #308 |
811 | 827 | B = repmat(uint8(zeros(1,1,size(alpha,3))),sz([1,2])); % Fix issue #307 %=zeros(sz([1,2]),'uint8'); |
|
825 | 841 | end |
826 | 842 | %} |
827 | 843 | % 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); |
829 | 847 | % Check for greyscale images |
830 | 848 | if options.colourspace == 2 |
831 | 849 | % Convert to greyscale |
@@ -1694,6 +1712,8 @@ function notify(filename) |
1694 | 1712 | 'crop', true, ... |
1695 | 1713 | 'crop_amounts', nan(1,4), ... % auto-crop all 4 image sides |
1696 | 1714 | 'transparent', false, ... |
| 1715 | + 'tcol', [], ... |
| 1716 | + 'ttol', uint8(25), ... % in [0,255] RGB color units |
1697 | 1717 | 'renderer', 0, ... % 0: default, 1: OpenGL, 2: ZBuffer, 3: Painters |
1698 | 1718 | 'pdf', false, ... |
1699 | 1719 | 'eps', false, ... |
@@ -1775,12 +1795,58 @@ function notify(filename) |
1775 | 1795 | else %if ischar(thisArg) && ~isempty(thisArg) |
1776 | 1796 | if thisArg(1) == '-' |
1777 | 1797 | addToOptionsStr = true; |
| 1798 | + [thisArg,extra] = strtok(thisArg,{'=','+'}); |
1778 | 1799 | switch lower(thisArg(2:end)) |
1779 | 1800 | case 'nocrop' |
1780 | 1801 | options.crop = false; |
1781 | 1802 | options.crop_amounts = [0,0,0,0]; |
1782 | 1803 | case {'trans', 'transparent'} |
1783 | 1804 | 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 |
1784 | 1850 | case 'opengl' |
1785 | 1851 | options.renderer = 1; |
1786 | 1852 | case 'zbuffer' |
@@ -1929,8 +1995,8 @@ function notify(filename) |
1929 | 1995 | error('export_fig:BadOptionValue','export_fig metadata must be a struct or cell-array of name-value pairs'); |
1930 | 1996 | end |
1931 | 1997 | 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"']; |
1934 | 2000 | skipNext = 1; |
1935 | 2001 | otherwise |
1936 | 2002 | try |
@@ -2098,6 +2164,11 @@ function notify(filename) |
2098 | 2164 | end |
2099 | 2165 | end |
2100 | 2166 |
|
| 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 | + |
2101 | 2172 | % Quick bail-out if no figure found |
2102 | 2173 | if isempty(fig), return; end |
2103 | 2174 |
|
@@ -2232,6 +2303,7 @@ function notify(filename) |
2232 | 2303 | end |
2233 | 2304 | end |
2234 | 2305 | end |
| 2306 | + |
2235 | 2307 | function options = setOptionsFormat(options, ext) |
2236 | 2308 | switch lower(ext(2:end)) |
2237 | 2309 | case {'tif', 'tiff'}, options.tif = true; |
@@ -2335,27 +2407,52 @@ function eps_remove_background(fname, count) |
2335 | 2407 | options.gif || options.im || options.alpha; |
2336 | 2408 | end |
2337 | 2409 |
|
2338 | | -function [A, tcol, alpha] = getFigImage(fig, magnify, renderer, options, pos) |
| 2410 | +function [A, bgcol, alpha] = getFigImage(fig, magnify, renderer, options, pos) |
2339 | 2411 | 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 |
2346 | 2437 | end |
| 2438 | + |
2347 | 2439 | % 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) |
2348 | 2450 | try |
2349 | 2451 | % 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); |
2351 | 2453 | catch |
2352 | 2454 | % 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'); |
2359 | 2456 | end |
2360 | 2457 | end |
2361 | 2458 |
|
|
0 commit comments