1 function exportfig(varargin) 2 %EXPORTFIG Export a figure to Encapsulated Postscript. 3 % EXPORTFIG(H, FILENAME) writes the figure H to FILENAME. H is 4 % a figure handle and FILENAME is a string that specifies the 5 % name of the output file. 6 % 7 % EXPORTFIG(...,PARAM1,VAL1,PARAM2,VAL2,...) specifies 8 % parameters that control various characteristics of the output 9 % file. 10 % 11 % Format Paramter: 12 % 'Format' one of the strings 'eps','eps2','jpeg','png','preview' 13 % specifies the output format. Defaults to 'eps'. 14 % The output format 'preview' does not generate an output 15 % file but instead creates a new figure window with a 16 % preview of the exported figure. In this case the 17 % FILENAME parameter is ignored. 18 % 19 % 'Preview' one of the strings 'none', 'tiff' 20 % specifies a preview for EPS files. Defaults to 'none'. 21 % 22 % Size Parameters: 23 % 'Width' a positive scalar 24 % specifies the width in the figure's PaperUnits 25 % 'Height' a positive scalar 26 % specifies the height in the figure's PaperUnits 27 % 28 % Specifying only one dimension sets the other dimension 29 % so that the exported aspect ratio is the same as the 30 % figure's current aspect ratio. 31 % If neither dimension is specified the size defaults to 32 % the width and height from the figure's PaperPosition. 33 % 34 % Rendering Parameters: 35 % 'Color' one of the strings 'bw', 'gray', 'cmyk' 36 % 'bw' specifies that lines and text are exported in 37 % black and all other objects in grayscale 38 % 'gray' specifies that all objects are exported in grayscale 39 % 'cmyk' specifies that all objects are exported in color 40 % using the CMYK color space 41 % 'Renderer' one of the strings 'painters', 'zbuffer', 'opengl' 42 % specifies the renderer to use 43 % 'Resolution' a positive scalar 44 % specifies the resolution in dots-per-inch. 45 % 46 % The default color setting is 'bw'. 47 % 48 % Font Parameters: 49 % 'FontMode' one of the strings 'scaled', 'fixed' 50 % 'FontSize' a positive scalar 51 % in 'scaled' mode multiplies with the font size of each 52 % text object to obtain the exported font size 53 % in 'fixed' mode specifies the font size of all text 54 % objects in points 55 % 'FontEncoding' one of the strings 'latin1', 'adobe' 56 % specifies the character encoding of the font 57 % 58 % If FontMode is 'scaled' but FontSize is not specified then a 59 % scaling factor is computed from the ratio of the size of the 60 % exported figure to the size of the actual figure. The minimum 61 % font size allowed after scaling is 5 points. 62 % If FontMode is 'fixed' but FontSize is not specified then the 63 % exported font sizes of all text objects is 7 points. 64 % 65 % The default 'FontMode' setting is 'scaled'. 66 % 67 % Line Width Parameters: 68 % 'LineMode' one of the strings 'scaled', 'fixed' 69 % 'LineWidth' a positive scalar 70 % the semantics of LineMode and LineWidth are exactly the 71 % same as FontMode and FontSize, except that they apply 72 % to line widths instead of font sizes. The minumum line 73 % width allowed after scaling is 0.5 points. 74 % If LineMode is 'fixed' but LineWidth is not specified 75 % then the exported line width of all line objects is 1 76 % point. 77 % 78 % Examples: 79 % exportfig(gcf,'fig1.eps','height',3); 80 % Exports the current figure to the file named 'fig1.eps' with 81 % a height of 3 inches (assuming the figure's PaperUnits is 82 % inches) and an aspect ratio the same as the figure's aspect 83 % ratio on screen. 84 % 85 % exportfig(gcf, 'fig2.eps', 'FontMode', 'fixed',... 86 % 'FontSize', 10, 'color', 'cmyk' ); 87 % Exports the current figure to 'fig2.eps' in color with all 88 % text in 10 point fonts. The size of the exported figure is 89 % the figure's PaperPostion width and height. 90 91 92 if (nargin < 2) 93 error('Too few input arguments'); 94 end 95 96 % exportfig(H, filename, ...) 97 H = varargin{1}; 98 if ~ishandle(H) | ~strcmp(get(H,'type'), 'figure') 99 error('First argument must be a handle to a figure.'); 100 end 101 filename = varargin{2}; 102 if ~ischar(filename) 103 error('Second argument must be a string.'); 104 end 105 paramPairs = varargin(3:end); 106 107 % Do some validity checking on param-value pairs 108 if (rem(length(paramPairs),2) ~= 0) 109 error(['Invalid input syntax. Optional parameters and values' ... 110 ' must be in pairs.']); 111 end 112 113 format = 'eps'; 114 preview = 'none'; 115 width = -1; 116 height = -1; 117 color = 'bw'; 118 fontsize = -1; 119 fontmode='scaled'; 120 linewidth = -1; 121 linemode=[]; 122 fontencoding = 'latin1'; 123 renderer = []; 124 resolution = []; 125 126 % Process param-value pairs 127 args = {}; 128 for k = 1:2:length(paramPairs) 129 param = lower(paramPairs{k}); 130 if (~ischar(param)) 131 error('Optional parameter names must be strings'); 132 end 133 value = paramPairs{k+1}; 134 135 switch (param) 136 case 'format' 137 format = value; 138 if (~strcmp(format,{'eps','eps2','jpeg','png','preview'})) 139 error(['Format must be ''eps'', ''eps2'', ''jpeg'', ''png'' or' ... 140 ' ''preview''.']); 141 end 142 case 'preview' 143 preview = value; 144 if (~strcmp(preview,{'none','tiff'})) 145 error('Preview must be ''none'' or ''tiff''.'); 146 end 147 case 'width' 148 width = LocalToNum(value); 149 if(~LocalIsPositiveScalar(width)) 150 error('Width must be a numeric scalar > 0'); 151 end 152 case 'height' 153 height = LocalToNum(value); 154 if(~LocalIsPositiveScalar(height)) 155 error('Height must be a numeric scalar > 0'); 156 end 157 case 'color' 158 color = lower(value); 159 if (~strcmp(color,{'bw','gray','cmyk'})) 160 error('Color must be ''bw'', ''gray'' or ''cmyk''.'); 161 end 162 case 'fontmode' 163 fontmode = lower(value); 164 if (~strcmp(fontmode,{'scaled','fixed'})) 165 error('FontMode must be ''scaled'' or ''fixed''.'); 166 end 167 case 'fontsize' 168 fontsize = LocalToNum(value); 169 if(~LocalIsPositiveScalar(fontsize)) 170 error('FontSize must be a numeric scalar > 0'); 171 end 172 case 'fontencoding' 173 fontencoding = lower(value); 174 if (~strcmp(fontencoding,{'latin1','adobe'})) 175 error('FontEncoding must be ''latin1'' or ''adobe''.'); 176 end 177 case 'linemode' 178 linemode = lower(value); 179 if (~strcmp(linemode,{'scaled','fixed'})) 180 error('LineMode must be ''scaled'' or ''fixed''.'); 181 end 182 case 'linewidth' 183 linewidth = LocalToNum(value); 184 if(~LocalIsPositiveScalar(linewidth)) 185 error('LineWidth must be a numeric scalar > 0'); 186 end 187 case 'renderer' 188 renderer = lower(value); 189 if (~strcmp(renderer,{'painters','zbuffer','opengl'})) 190 error('Renderer must be ''painters'', ''zbuffer'' or ''opengl''.'); 191 end 192 case 'resolution' 193 resolution = LocalToNum(value); 194 if ~(isnumeric(value) & (prod(size(value)) == 1) & (value >= 0)); 195 error('Resolution must be a numeric scalar >= 0'); 196 end 197 otherwise 198 error(['Unrecognized option ' param '.']); 199 end 200 end 201 202 allLines = findall(H, 'type', 'line'); 203 allText = findall(H, 'type', 'text'); 204 allAxes = findall(H, 'type', 'axes'); 205 allImages = findall(H, 'type', 'image'); 206 allLights = findall(H, 'type', 'light'); 207 allPatch = findall(H, 'type', 'patch'); 208 allSurf = findall(H, 'type', 'surface'); 209 allRect = findall(H, 'type', 'rectangle'); 210 allFont = [allText; allAxes]; 211 allColor = [allLines; allText; allAxes; allLights]; 212 allMarker = [allLines; allPatch; allSurf]; 213 allEdge = [allPatch; allSurf]; 214 allCData = [allImages; allPatch; allSurf]; 215 216 old.objs = {}; 217 old.prop = {}; 218 old.values = {}; 219 220 % Process format and preview parameter 221 showPreview = strcmp(format,'preview'); 222 if showPreview 223 format = 'png'; 224 filename = [tempName '.png']; 225 end 226 if strncmp(format,'eps',3) & ~strcmp(preview,'none') 227 args = {args{:}, ['-' preview]}; 228 end 229 230 hadError = 0; 231 try 232 % Process size parameters 233 paperPos = get(H, 'PaperPosition'); 234 old = LocalPushOldData(old, H, 'PaperPosition', paperPos); 235 figureUnits = get(H, 'Units'); 236 set(H, 'Units', get(H,'PaperUnits')); 237 figurePos = get(H, 'Position'); 238 aspectRatio = figurePos(3)/figurePos(4); 239 set(H, 'Units', figureUnits); 240 if (width == -1) & (height == -1) 241 width = paperPos(3); 242 height = paperPos(4); 243 elseif (width == -1) 244 width = height * aspectRatio; 245 elseif (height == -1) 246 height = width / aspectRatio; 247 end 248 set(H, 'PaperPosition', [0 0 width height]); 249 paperPosMode = get(H, 'PaperPositionMode'); 250 old = LocalPushOldData(old, H, 'PaperPositionMode', paperPosMode); 251 set(H, 'PaperPositionMode', 'manual'); 252 253 % Process rendering parameters 254 switch (color) 255 case {'bw', 'gray'} 256 if ~strcmp(color,'bw') & strncmp(format,'eps',3) 257 format = [format 'c']; 258 end 259 args = {args{:}, ['-d' format]}; 260 261 %compute and set gray colormap 262 oldcmap = get(H,'Colormap'); 263 newgrays = 0.30*oldcmap(:,1) + 0.59*oldcmap(:,2) + 0.11*oldcmap(:,3); 264 newcmap = [newgrays newgrays newgrays]; 265 old = LocalPushOldData(old, H, 'Colormap', oldcmap); 266 set(H, 'Colormap', newcmap); 267 268 %compute and set ColorSpec and CData properties 269 old = LocalUpdateColors(allColor, 'color', old); 270 old = LocalUpdateColors(allAxes, 'xcolor', old); 271 old = LocalUpdateColors(allAxes, 'ycolor', old); 272 old = LocalUpdateColors(allAxes, 'zcolor', old); 273 old = LocalUpdateColors(allMarker, 'MarkerEdgeColor', old); 274 old = LocalUpdateColors(allMarker, 'MarkerFaceColor', old); 275 old = LocalUpdateColors(allEdge, 'EdgeColor', old); 276 old = LocalUpdateColors(allEdge, 'FaceColor', old); 277 old = LocalUpdateColors(allCData, 'CData', old); 278 279 case 'cmyk' 280 if strncmp(format,'eps',3) 281 format = [format 'c']; 282 args = {args{:}, ['-d' format], '-cmyk'}; 283 else 284 args = {args{:}, ['-d' format]}; 285 end 286 otherwise 287 error('Invalid Color parameter'); 288 end 289 if (~isempty(renderer)) 290 args = {args{:}, ['-' renderer]}; 291 end 292 if (~isempty(resolution)) | ~strncmp(format,'eps',3) 293 if isempty(resolution) 294 resolution = 0; 295 end 296 args = {args{:}, ['-r' int2str(resolution)]}; 297 end 298 299 % Process font parameters 300 if (~isempty(fontmode)) 301 oldfonts = LocalGetAsCell(allFont,'FontSize'); 302 switch (fontmode) 303 case 'fixed' 304 oldfontunits = LocalGetAsCell(allFont,'FontUnits'); 305 old = LocalPushOldData(old, allFont, {'FontUnits'}, oldfontunits); 306 set(allFont,'FontUnits','points'); 307 if (fontsize == -1) 308 set(allFont,'FontSize',7); 309 else 310 set(allFont,'FontSize',fontsize); 311 end 312 case 'scaled' 313 if (fontsize == -1) 314 wscale = width/figurePos(3); 315 hscale = height/figurePos(4); 316 scale = min(wscale, hscale); 317 else 318 scale = fontsize; 319 end 320 newfonts = LocalScale(oldfonts,scale,5); 321 set(allFont,{'FontSize'},newfonts); 322 otherwise 323 error('Invalid FontMode parameter'); 324 end 325 % make sure we push the size after the units 326 old = LocalPushOldData(old, allFont, {'FontSize'}, oldfonts); 327 end 328 if strcmp(fontencoding,'adobe') & strncmp(format,'eps',3) 329 args = {args{:}, '-adobecset'}; 330 end 331 332 % Process linewidth parameters 333 if (~isempty(linemode)) 334 oldlines = LocalGetAsCell(allMarker,'LineWidth'); 335 old = LocalPushOldData(old, allMarker, {'LineWidth'}, oldlines); 336 switch (linemode) 337 case 'fixed' 338 if (linewidth == -1) 339 set(allMarker,'LineWidth',1); 340 else 341 set(allMarker,'LineWidth',linewidth); 342 end 343 case 'scaled' 344 if (linewidth == -1) 345 wscale = width/figurePos(3); 346 hscale = height/figurePos(4); 347 scale = min(wscale, hscale); 348 else 349 scale = linewidth; 350 end 351 newlines = LocalScale(oldlines, scale, 0.5); 352 set(allMarker,{'LineWidth'},newlines); 353 otherwise 354 error('Invalid LineMode parameter'); 355 end 356 end 357 358 % Export 359 print(H, filename, args{:}); 360 361 catch 362 hadError = 1; 363 end 364 365 % Restore figure settings 366 for n=1:length(old.objs) 367 set(old.objs{n}, old.prop{n}, old.values{n}); 368 end 369 370 if hadError 371 error(deblank(lasterr)); 372 end 373 374 % Show preview if requested 375 if showPreview 376 X = imread(filename,'png'); 377 delete(filename); 378 f = figure( 'Name', 'Preview', ... 379 'Menubar', 'none', ... 380 'NumberTitle', 'off', ... 381 'Visible', 'off'); 382 image(X); 383 axis image; 384 ax = findobj(f, 'type', 'axes'); 385 set(ax, 'Units', get(H,'PaperUnits'), ... 386 'Position', [0 0 width height], ... 387 'Visible', 'off'); 388 set(ax, 'Units', 'pixels'); 389 axesPos = get(ax,'Position'); 390 figPos = get(f,'Position'); 391 rootSize = get(0,'ScreenSize'); 392 figPos(3:4) = axesPos(3:4); 393 if figPos(1) + figPos(3) > rootSize(3) 394 figPos(1) = rootSize(3) - figPos(3) - 50; 395 end 396 if figPos(2) + figPos(4) > rootSize(4) 397 figPos(2) = rootSize(4) - figPos(4) - 50; 398 end 399 set(f, 'Position',figPos, ... 400 'Visible', 'on'); 401 end 402 403 % 404 % Local Functions 405 % 406 407 function outData = LocalPushOldData(inData, objs, prop, values) 408 outData.objs = {inData.objs{:}, objs}; 409 outData.prop = {inData.prop{:}, prop}; 410 outData.values = {inData.values{:}, values}; 411 412 function cellArray = LocalGetAsCell(fig,prop); 413 cellArray = get(fig,prop); 414 if (~isempty(cellArray)) & (~iscell(cellArray)) 415 cellArray = {cellArray}; 416 end 417 418 function newArray = LocalScale(inArray, scale, minValue) 419 n = length(inArray); 420 newArray = cell(n,1); 421 for k=1:n 422 newArray{k} = max(minValue,scale*inArray{k}(1)); 423 end 424 425 function newArray = LocalMapToGray(inArray); 426 n = length(inArray); 427 newArray = cell(n,1); 428 for k=1:n 429 color = inArray{k}; 430 if (~isempty(color)) 431 if ischar(color) 432 switch color(1) 433 case 'y' 434 color = [1 1 0]; 435 case 'm' 436 color = [1 0 1]; 437 case 'c' 438 color = [0 1 1]; 439 case 'r' 440 color = [1 0 0]; 441 case 'g' 442 color = [0 1 0]; 443 case 'b' 444 color = [0 0 1]; 445 case 'w' 446 color = [1 1 1]; 447 case 'k' 448 color = [0 0 0]; 449 otherwise 450 newArray{k} = color; 451 end 452 end 453 if ~ischar(color) 454 color = 0.30*color(1) + 0.59*color(2) + 0.11*color(3); 455 end 456 end 457 if isempty(color) | ischar(color) 458 newArray{k} = color; 459 else 460 newArray{k} = [color color color]; 461 end 462 end 463 464 function newArray = LocalMapCData(inArray); 465 n = length(inArray); 466 newArray = cell(n,1); 467 for k=1:n 468 color = inArray{k}; 469 if (ndims(color) == 3) & isa(color,'double') 470 gray = 0.30*color(:,:,1) + 0.59*color(:,:,2) + 0.11*color(:,:,3); 471 color(:,:,1) = gray; 472 color(:,:,2) = gray; 473 color(:,:,3) = gray; 474 end 475 newArray{k} = color; 476 end 477 478 function outData = LocalUpdateColors(inArray, prop, inData) 479 value = LocalGetAsCell(inArray,prop); 480 outData.objs = {inData.objs{:}, inArray}; 481 outData.prop = {inData.prop{:}, {prop}}; 482 outData.values = {inData.values{:}, value}; 483 if (~isempty(value)) 484 if strcmp(prop,'CData') 485 value = LocalMapCData(value); 486 else 487 value = LocalMapToGray(value); 488 end 489 set(inArray,{prop},value); 490 end 491 492 function bool = LocalIsPositiveScalar(value) 493 bool = isnumeric(value) & ... 494 prod(size(value)) == 1 & ... 495 value > 0; 496 497 function value = LocalToNum(value) 498 if ischar(value) 499 value = str2num(value); 500 end 501