|
a |
|
b/util/export_fig/print2array.m |
|
|
1 |
function [A, bcol] = print2array(fig, res, renderer, gs_options) |
|
|
2 |
%PRINT2ARRAY Exports a figure to an image array |
|
|
3 |
% |
|
|
4 |
% Examples: |
|
|
5 |
% A = print2array |
|
|
6 |
% A = print2array(figure_handle) |
|
|
7 |
% A = print2array(figure_handle, resolution) |
|
|
8 |
% A = print2array(figure_handle, resolution, renderer) |
|
|
9 |
% A = print2array(figure_handle, resolution, renderer, gs_options) |
|
|
10 |
% [A bcol] = print2array(...) |
|
|
11 |
% |
|
|
12 |
% This function outputs a bitmap image of the given figure, at the desired |
|
|
13 |
% resolution. |
|
|
14 |
% |
|
|
15 |
% If renderer is '-painters' then ghostcript needs to be installed. This |
|
|
16 |
% can be downloaded from: http://www.ghostscript.com |
|
|
17 |
% |
|
|
18 |
% IN: |
|
|
19 |
% figure_handle - The handle of the figure to be exported. Default: gcf. |
|
|
20 |
% resolution - Resolution of the output, as a factor of screen |
|
|
21 |
% resolution. Default: 1. |
|
|
22 |
% renderer - string containing the renderer paramater to be passed to |
|
|
23 |
% print. Default: '-opengl'. |
|
|
24 |
% gs_options - optional ghostscript options (e.g.: '-dNoOutputFonts'). If |
|
|
25 |
% multiple options are needed, enclose in call array: {'-a','-b'} |
|
|
26 |
% |
|
|
27 |
% OUT: |
|
|
28 |
% A - MxNx3 uint8 image of the figure. |
|
|
29 |
% bcol - 1x3 uint8 vector of the background color |
|
|
30 |
|
|
|
31 |
% Copyright (C) Oliver Woodford 2008-2014, Yair Altman 2015- |
|
|
32 |
%{ |
|
|
33 |
% 05/09/11: Set EraseModes to normal when using opengl or zbuffer |
|
|
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. |
|
|
39 |
% 09/12/11: Pass font path to ghostscript. |
|
|
40 |
% 27/01/12: Bug fix affecting painters rendering tall figures. Thanks to |
|
|
41 |
% Ken Campbell for reporting it. |
|
|
42 |
% 03/04/12: Bug fix to median input. Thanks to Andy Matthews for reporting it. |
|
|
43 |
% 26/10/12: Set PaperOrientation to portrait. Thanks to Michael Watts for |
|
|
44 |
% 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 |
% 11/12/16: Fixed cropping issue reported by Harry D. |
|
|
53 |
%} |
|
|
54 |
|
|
|
55 |
% Generate default input arguments, if needed |
|
|
56 |
if nargin < 2 |
|
|
57 |
res = 1; |
|
|
58 |
if nargin < 1 |
|
|
59 |
fig = gcf; |
|
|
60 |
end |
|
|
61 |
end |
|
|
62 |
% Warn if output is large |
|
|
63 |
old_mode = get(fig, 'Units'); |
|
|
64 |
set(fig, 'Units', 'pixels'); |
|
|
65 |
px = get(fig, 'Position'); |
|
|
66 |
set(fig, 'Units', old_mode); |
|
|
67 |
npx = prod(px(3:4)*res)/1e6; |
|
|
68 |
if npx > 30 |
|
|
69 |
% 30M pixels or larger! |
|
|
70 |
warning('MATLAB:LargeImage', 'print2array generating a %.1fM pixel image. This could be slow and might also cause memory problems.', npx); |
|
|
71 |
end |
|
|
72 |
% Retrieve the background colour |
|
|
73 |
bcol = get(fig, 'Color'); |
|
|
74 |
% Set the resolution parameter |
|
|
75 |
res_str = ['-r' num2str(ceil(get(0, 'ScreenPixelsPerInch')*res))]; |
|
|
76 |
% Generate temporary file name |
|
|
77 |
tmp_nam = [tempname '.tif']; |
|
|
78 |
try |
|
|
79 |
% Ensure that the temp dir is writable (Javier Paredes 26/2/15) |
|
|
80 |
fid = fopen(tmp_nam,'w'); |
|
|
81 |
fwrite(fid,1); |
|
|
82 |
fclose(fid); |
|
|
83 |
delete(tmp_nam); % cleanup |
|
|
84 |
isTempDirOk = true; |
|
|
85 |
catch |
|
|
86 |
% Temp dir is not writable, so use the current folder |
|
|
87 |
[dummy,fname,fext] = fileparts(tmp_nam); %#ok<ASGLU> |
|
|
88 |
fpath = pwd; |
|
|
89 |
tmp_nam = fullfile(fpath,[fname fext]); |
|
|
90 |
isTempDirOk = false; |
|
|
91 |
end |
|
|
92 |
% Enable users to specify optional ghostscript options (issue #36) |
|
|
93 |
if nargin > 3 && ~isempty(gs_options) |
|
|
94 |
if iscell(gs_options) |
|
|
95 |
gs_options = sprintf(' %s',gs_options{:}); |
|
|
96 |
elseif ~ischar(gs_options) |
|
|
97 |
error('gs_options input argument must be a string or cell-array of strings'); |
|
|
98 |
else |
|
|
99 |
gs_options = [' ' gs_options]; |
|
|
100 |
end |
|
|
101 |
else |
|
|
102 |
gs_options = ''; |
|
|
103 |
end |
|
|
104 |
if nargin > 2 && strcmp(renderer, '-painters') |
|
|
105 |
% First try to print directly to tif file |
|
|
106 |
try |
|
|
107 |
% Print the file into a temporary TIF file and read it into array A |
|
|
108 |
[A, err, ex] = read_tif_img(fig, res_str, renderer, tmp_nam); |
|
|
109 |
if err, rethrow(ex); end |
|
|
110 |
catch % error - try to print to EPS and then using Ghostscript to TIF |
|
|
111 |
% Print to eps file |
|
|
112 |
if isTempDirOk |
|
|
113 |
tmp_eps = [tempname '.eps']; |
|
|
114 |
else |
|
|
115 |
tmp_eps = fullfile(fpath,[fname '.eps']); |
|
|
116 |
end |
|
|
117 |
print2eps(tmp_eps, fig, 0, renderer, '-loose'); |
|
|
118 |
try |
|
|
119 |
% Initialize the command to export to tiff using ghostscript |
|
|
120 |
cmd_str = ['-dEPSCrop -q -dNOPAUSE -dBATCH ' res_str ' -sDEVICE=tiff24nc']; |
|
|
121 |
% Set the font path |
|
|
122 |
fp = font_path(); |
|
|
123 |
if ~isempty(fp) |
|
|
124 |
cmd_str = [cmd_str ' -sFONTPATH="' fp '"']; |
|
|
125 |
end |
|
|
126 |
% Add the filenames |
|
|
127 |
cmd_str = [cmd_str ' -sOutputFile="' tmp_nam '" "' tmp_eps '"' gs_options]; |
|
|
128 |
% Execute the ghostscript command |
|
|
129 |
ghostscript(cmd_str); |
|
|
130 |
catch me |
|
|
131 |
% Delete the intermediate file |
|
|
132 |
delete(tmp_eps); |
|
|
133 |
rethrow(me); |
|
|
134 |
end |
|
|
135 |
% Delete the intermediate file |
|
|
136 |
delete(tmp_eps); |
|
|
137 |
% Read in the generated bitmap |
|
|
138 |
A = imread(tmp_nam); |
|
|
139 |
% Delete the temporary bitmap file |
|
|
140 |
delete(tmp_nam); |
|
|
141 |
end |
|
|
142 |
% Set border pixels to the correct colour |
|
|
143 |
if isequal(bcol, 'none') |
|
|
144 |
bcol = []; |
|
|
145 |
elseif isequal(bcol, [1 1 1]) |
|
|
146 |
bcol = uint8([255 255 255]); |
|
|
147 |
else |
|
|
148 |
for l = 1:size(A, 2) |
|
|
149 |
if ~all(reshape(A(:,l,:) == 255, [], 1)) |
|
|
150 |
break; |
|
|
151 |
end |
|
|
152 |
end |
|
|
153 |
for r = size(A, 2):-1:l |
|
|
154 |
if ~all(reshape(A(:,r,:) == 255, [], 1)) |
|
|
155 |
break; |
|
|
156 |
end |
|
|
157 |
end |
|
|
158 |
for t = 1:size(A, 1) |
|
|
159 |
if ~all(reshape(A(t,:,:) == 255, [], 1)) |
|
|
160 |
break; |
|
|
161 |
end |
|
|
162 |
end |
|
|
163 |
for b = size(A, 1):-1:t |
|
|
164 |
if ~all(reshape(A(b,:,:) == 255, [], 1)) |
|
|
165 |
break; |
|
|
166 |
end |
|
|
167 |
end |
|
|
168 |
bcol = uint8(median(single([reshape(A(:,[l r],:), [], size(A, 3)); reshape(A([t b],:,:), [], size(A, 3))]), 1)); |
|
|
169 |
for c = 1:size(A, 3) |
|
|
170 |
A(:,[1:l-1, r+1:end],c) = bcol(c); |
|
|
171 |
A([1:t-1, b+1:end],:,c) = bcol(c); |
|
|
172 |
end |
|
|
173 |
end |
|
|
174 |
else |
|
|
175 |
if nargin < 3 |
|
|
176 |
renderer = '-opengl'; |
|
|
177 |
end |
|
|
178 |
% Print the file into a temporary TIF file and read it into array A |
|
|
179 |
[A, err, ex] = read_tif_img(fig, res_str, renderer, tmp_nam); |
|
|
180 |
% Throw any error that occurred |
|
|
181 |
if err |
|
|
182 |
% Display suggested workarounds to internal print() error (issue #16) |
|
|
183 |
fprintf(2, 'An error occured with Matlab''s builtin print function.\nTry setting the figure Renderer to ''painters'' or use opengl(''software'').\n\n'); |
|
|
184 |
rethrow(ex); |
|
|
185 |
end |
|
|
186 |
% Set the background color |
|
|
187 |
if isequal(bcol, 'none') |
|
|
188 |
bcol = []; |
|
|
189 |
else |
|
|
190 |
bcol = bcol * 255; |
|
|
191 |
if isequal(bcol, round(bcol)) |
|
|
192 |
bcol = uint8(bcol); |
|
|
193 |
else |
|
|
194 |
bcol = squeeze(A(1,1,:)); |
|
|
195 |
end |
|
|
196 |
end |
|
|
197 |
end |
|
|
198 |
% Check the output size is correct |
|
|
199 |
if isequal(res, round(res)) |
|
|
200 |
px = round([px([4 3])*res 3]); % round() to avoid an indexing warning below |
|
|
201 |
if ~isequal(size(A), px) |
|
|
202 |
% Correct the output size |
|
|
203 |
A = A(1:min(end,px(1)),1:min(end,px(2)),:); |
|
|
204 |
end |
|
|
205 |
end |
|
|
206 |
end |
|
|
207 |
|
|
|
208 |
% Function to create a TIF image of the figure and read it into an array |
|
|
209 |
function [A, err, ex] = read_tif_img(fig, res_str, renderer, tmp_nam) |
|
|
210 |
err = false; |
|
|
211 |
ex = []; |
|
|
212 |
% Temporarily set the paper size |
|
|
213 |
old_pos_mode = get(fig, 'PaperPositionMode'); |
|
|
214 |
old_orientation = get(fig, 'PaperOrientation'); |
|
|
215 |
set(fig, 'PaperPositionMode','auto', 'PaperOrientation','portrait'); |
|
|
216 |
try |
|
|
217 |
% Workaround for issue #69: patches with LineWidth==0.75 appear wide (internal bug in Matlab's print() function) |
|
|
218 |
fp = []; % in case we get an error below |
|
|
219 |
fp = findall(fig, 'Type','patch', 'LineWidth',0.75); |
|
|
220 |
set(fp, 'LineWidth',0.5); |
|
|
221 |
% Fix issue #83: use numeric handles in HG1 |
|
|
222 |
if ~using_hg2(fig), fig = double(fig); end |
|
|
223 |
% Print to tiff file |
|
|
224 |
print(fig, renderer, res_str, '-dtiff', tmp_nam); |
|
|
225 |
% Read in the printed file |
|
|
226 |
A = imread(tmp_nam); |
|
|
227 |
% Delete the temporary file |
|
|
228 |
delete(tmp_nam); |
|
|
229 |
catch ex |
|
|
230 |
err = true; |
|
|
231 |
end |
|
|
232 |
set(fp, 'LineWidth',0.75); % restore original figure appearance |
|
|
233 |
% Reset the paper size |
|
|
234 |
set(fig, 'PaperPositionMode',old_pos_mode, 'PaperOrientation',old_orientation); |
|
|
235 |
end |
|
|
236 |
|
|
|
237 |
% Function to return (and create, where necessary) the font path |
|
|
238 |
function fp = font_path() |
|
|
239 |
fp = user_string('gs_font_path'); |
|
|
240 |
if ~isempty(fp) |
|
|
241 |
return |
|
|
242 |
end |
|
|
243 |
% Create the path |
|
|
244 |
% Start with the default path |
|
|
245 |
fp = getenv('GS_FONTPATH'); |
|
|
246 |
% Add on the typical directories for a given OS |
|
|
247 |
if ispc |
|
|
248 |
if ~isempty(fp) |
|
|
249 |
fp = [fp ';']; |
|
|
250 |
end |
|
|
251 |
fp = [fp getenv('WINDIR') filesep 'Fonts']; |
|
|
252 |
else |
|
|
253 |
if ~isempty(fp) |
|
|
254 |
fp = [fp ':']; |
|
|
255 |
end |
|
|
256 |
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']; |
|
|
257 |
end |
|
|
258 |
user_string('gs_font_path', fp); |
|
|
259 |
end |