function exportfig(varargin) %EXPORTFIG Export a figure to Encapsulated Postscript. % EXPORTFIG(H, FILENAME) writes the figure H to FILENAME. H is % a figure handle and FILENAME is a string that specifies the % name of the output file. % % EXPORTFIG(...,PARAM1,VAL1,PARAM2,VAL2,...) specifies % parameters that control various characteristics of the output % file. % % Format Paramter: % 'Format' one of the strings 'eps','eps2','jpeg','png','preview' % specifies the output format. Defaults to 'eps'. % The output format 'preview' does not generate an output % file but instead creates a new figure window with a % preview of the exported figure. In this case the % FILENAME parameter is ignored. % % 'Preview' one of the strings 'none', 'tiff' % specifies a preview for EPS files. Defaults to 'none'. % % Size Parameters: % 'Width' a positive scalar % specifies the width in the figure's PaperUnits % 'Height' a positive scalar % specifies the height in the figure's PaperUnits % % Specifying only one dimension sets the other dimension % so that the exported aspect ratio is the same as the % figure's current aspect ratio. % If neither dimension is specified the size defaults to % the width and height from the figure's PaperPosition. % % Rendering Parameters: % 'Color' one of the strings 'bw', 'gray', 'cmyk' % 'bw' specifies that lines and text are exported in % black and all other objects in grayscale % 'gray' specifies that all objects are exported in grayscale % 'cmyk' specifies that all objects are exported in color % using the CMYK color space % 'Renderer' one of the strings 'painters', 'zbuffer', 'opengl' % specifies the renderer to use % 'Resolution' a positive scalar % specifies the resolution in dots-per-inch. % % The default color setting is 'bw'. % % Font Parameters: % 'FontMode' one of the strings 'scaled', 'fixed' % 'FontSize' a positive scalar % in 'scaled' mode multiplies with the font size of each % text object to obtain the exported font size % in 'fixed' mode specifies the font size of all text % objects in points % 'FontEncoding' one of the strings 'latin1', 'adobe' % specifies the character encoding of the font % % If FontMode is 'scaled' but FontSize is not specified then a % scaling factor is computed from the ratio of the size of the % exported figure to the size of the actual figure. The minimum % font size allowed after scaling is 5 points. % If FontMode is 'fixed' but FontSize is not specified then the % exported font sizes of all text objects is 7 points. % % The default 'FontMode' setting is 'scaled'. % % Line Width Parameters: % 'LineMode' one of the strings 'scaled', 'fixed' % 'LineWidth' a positive scalar % the semantics of LineMode and LineWidth are exactly the % same as FontMode and FontSize, except that they apply % to line widths instead of font sizes. The minumum line % width allowed after scaling is 0.5 points. % If LineMode is 'fixed' but LineWidth is not specified % then the exported line width of all line objects is 1 % point. % % Examples: % exportfig(gcf,'fig1.eps','height',3); % Exports the current figure to the file named 'fig1.eps' with % a height of 3 inches (assuming the figure's PaperUnits is % inches) and an aspect ratio the same as the figure's aspect % ratio on screen. % % exportfig(gcf, 'fig2.eps', 'FontMode', 'fixed',... % 'FontSize', 10, 'color', 'cmyk' ); % Exports the current figure to 'fig2.eps' in color with all % text in 10 point fonts. The size of the exported figure is % the figure's PaperPostion width and height. if (nargin < 2) error('Too few input arguments'); end % exportfig(H, filename, ...) H = varargin{1}; if ~ishandle(H) | ~strcmp(get(H,'type'), 'figure') error('First argument must be a handle to a figure.'); end filename = varargin{2}; if ~ischar(filename) error('Second argument must be a string.'); end paramPairs = varargin(3:end); % Do some validity checking on param-value pairs if (rem(length(paramPairs),2) ~= 0) error(['Invalid input syntax. Optional parameters and values' ... ' must be in pairs.']); end format = 'eps'; preview = 'none'; width = -1; height = -1; color = 'bw'; fontsize = -1; fontmode='scaled'; linewidth = -1; linemode=[]; fontencoding = 'latin1'; renderer = []; resolution = []; % Process param-value pairs args = {}; for k = 1:2:length(paramPairs) param = lower(paramPairs{k}); if (~ischar(param)) error('Optional parameter names must be strings'); end value = paramPairs{k+1}; switch (param) case 'format' format = value; if (~strcmp(format,{'eps','eps2','jpeg','png','preview'})) error(['Format must be ''eps'', ''eps2'', ''jpeg'', ''png'' or' ... ' ''preview''.']); end case 'preview' preview = value; if (~strcmp(preview,{'none','tiff'})) error('Preview must be ''none'' or ''tiff''.'); end case 'width' width = LocalToNum(value); if(~LocalIsPositiveScalar(width)) error('Width must be a numeric scalar > 0'); end case 'height' height = LocalToNum(value); if(~LocalIsPositiveScalar(height)) error('Height must be a numeric scalar > 0'); end case 'color' color = lower(value); if (~strcmp(color,{'bw','gray','cmyk'})) error('Color must be ''bw'', ''gray'' or ''cmyk''.'); end case 'fontmode' fontmode = lower(value); if (~strcmp(fontmode,{'scaled','fixed'})) error('FontMode must be ''scaled'' or ''fixed''.'); end case 'fontsize' fontsize = LocalToNum(value); if(~LocalIsPositiveScalar(fontsize)) error('FontSize must be a numeric scalar > 0'); end case 'fontencoding' fontencoding = lower(value); if (~strcmp(fontencoding,{'latin1','adobe'})) error('FontEncoding must be ''latin1'' or ''adobe''.'); end case 'linemode' linemode = lower(value); if (~strcmp(linemode,{'scaled','fixed'})) error('LineMode must be ''scaled'' or ''fixed''.'); end case 'linewidth' linewidth = LocalToNum(value); if(~LocalIsPositiveScalar(linewidth)) error('LineWidth must be a numeric scalar > 0'); end case 'renderer' renderer = lower(value); if (~strcmp(renderer,{'painters','zbuffer','opengl'})) error('Renderer must be ''painters'', ''zbuffer'' or ''opengl''.'); end case 'resolution' resolution = LocalToNum(value); if ~(isnumeric(value) & (prod(size(value)) == 1) & (value >= 0)); error('Resolution must be a numeric scalar >= 0'); end otherwise error(['Unrecognized option ' param '.']); end end allLines = findall(H, 'type', 'line'); allText = findall(H, 'type', 'text'); allAxes = findall(H, 'type', 'axes'); allImages = findall(H, 'type', 'image'); allLights = findall(H, 'type', 'light'); allPatch = findall(H, 'type', 'patch'); allSurf = findall(H, 'type', 'surface'); allRect = findall(H, 'type', 'rectangle'); allFont = [allText; allAxes]; allColor = [allLines; allText; allAxes; allLights]; allMarker = [allLines; allPatch; allSurf]; allEdge = [allPatch; allSurf]; allCData = [allImages; allPatch; allSurf]; old.objs = {}; old.prop = {}; old.values = {}; % Process format and preview parameter showPreview = strcmp(format,'preview'); if showPreview format = 'png'; filename = [tempName '.png']; end if strncmp(format,'eps',3) & ~strcmp(preview,'none') args = {args{:}, ['-' preview]}; end hadError = 0; try % Process size parameters paperPos = get(H, 'PaperPosition'); old = LocalPushOldData(old, H, 'PaperPosition', paperPos); figureUnits = get(H, 'Units'); set(H, 'Units', get(H,'PaperUnits')); figurePos = get(H, 'Position'); aspectRatio = figurePos(3)/figurePos(4); set(H, 'Units', figureUnits); if (width == -1) & (height == -1) width = paperPos(3); height = paperPos(4); elseif (width == -1) width = height * aspectRatio; elseif (height == -1) height = width / aspectRatio; end set(H, 'PaperPosition', [0 0 width height]); paperPosMode = get(H, 'PaperPositionMode'); old = LocalPushOldData(old, H, 'PaperPositionMode', paperPosMode); set(H, 'PaperPositionMode', 'manual'); % Process rendering parameters switch (color) case {'bw', 'gray'} if ~strcmp(color,'bw') & strncmp(format,'eps',3) format = [format 'c']; end args = {args{:}, ['-d' format]}; %compute and set gray colormap oldcmap = get(H,'Colormap'); newgrays = 0.30*oldcmap(:,1) + 0.59*oldcmap(:,2) + 0.11*oldcmap(:,3); newcmap = [newgrays newgrays newgrays]; old = LocalPushOldData(old, H, 'Colormap', oldcmap); set(H, 'Colormap', newcmap); %compute and set ColorSpec and CData properties old = LocalUpdateColors(allColor, 'color', old); old = LocalUpdateColors(allAxes, 'xcolor', old); old = LocalUpdateColors(allAxes, 'ycolor', old); old = LocalUpdateColors(allAxes, 'zcolor', old); old = LocalUpdateColors(allMarker, 'MarkerEdgeColor', old); old = LocalUpdateColors(allMarker, 'MarkerFaceColor', old); old = LocalUpdateColors(allEdge, 'EdgeColor', old); old = LocalUpdateColors(allEdge, 'FaceColor', old); old = LocalUpdateColors(allCData, 'CData', old); case 'cmyk' if strncmp(format,'eps',3) format = [format 'c']; args = {args{:}, ['-d' format], '-cmyk'}; else args = {args{:}, ['-d' format]}; end otherwise error('Invalid Color parameter'); end if (~isempty(renderer)) args = {args{:}, ['-' renderer]}; end if (~isempty(resolution)) | ~strncmp(format,'eps',3) if isempty(resolution) resolution = 0; end args = {args{:}, ['-r' int2str(resolution)]}; end % Process font parameters if (~isempty(fontmode)) oldfonts = LocalGetAsCell(allFont,'FontSize'); switch (fontmode) case 'fixed' oldfontunits = LocalGetAsCell(allFont,'FontUnits'); old = LocalPushOldData(old, allFont, {'FontUnits'}, oldfontunits); set(allFont,'FontUnits','points'); if (fontsize == -1) set(allFont,'FontSize',7); else set(allFont,'FontSize',fontsize); end case 'scaled' if (fontsize == -1) wscale = width/figurePos(3); hscale = height/figurePos(4); scale = min(wscale, hscale); else scale = fontsize; end newfonts = LocalScale(oldfonts,scale,5); set(allFont,{'FontSize'},newfonts); otherwise error('Invalid FontMode parameter'); end % make sure we push the size after the units old = LocalPushOldData(old, allFont, {'FontSize'}, oldfonts); end if strcmp(fontencoding,'adobe') & strncmp(format,'eps',3) args = {args{:}, '-adobecset'}; end % Process linewidth parameters if (~isempty(linemode)) oldlines = LocalGetAsCell(allMarker,'LineWidth'); old = LocalPushOldData(old, allMarker, {'LineWidth'}, oldlines); switch (linemode) case 'fixed' if (linewidth == -1) set(allMarker,'LineWidth',1); else set(allMarker,'LineWidth',linewidth); end case 'scaled' if (linewidth == -1) wscale = width/figurePos(3); hscale = height/figurePos(4); scale = min(wscale, hscale); else scale = linewidth; end newlines = LocalScale(oldlines, scale, 0.5); set(allMarker,{'LineWidth'},newlines); otherwise error('Invalid LineMode parameter'); end end % Export print(H, filename, args{:}); catch hadError = 1; end % Restore figure settings for n=1:length(old.objs) set(old.objs{n}, old.prop{n}, old.values{n}); end if hadError error(deblank(lasterr)); end % Show preview if requested if showPreview X = imread(filename,'png'); delete(filename); f = figure( 'Name', 'Preview', ... 'Menubar', 'none', ... 'NumberTitle', 'off', ... 'Visible', 'off'); image(X); axis image; ax = findobj(f, 'type', 'axes'); set(ax, 'Units', get(H,'PaperUnits'), ... 'Position', [0 0 width height], ... 'Visible', 'off'); set(ax, 'Units', 'pixels'); axesPos = get(ax,'Position'); figPos = get(f,'Position'); rootSize = get(0,'ScreenSize'); figPos(3:4) = axesPos(3:4); if figPos(1) + figPos(3) > rootSize(3) figPos(1) = rootSize(3) - figPos(3) - 50; end if figPos(2) + figPos(4) > rootSize(4) figPos(2) = rootSize(4) - figPos(4) - 50; end set(f, 'Position',figPos, ... 'Visible', 'on'); end % % Local Functions % function outData = LocalPushOldData(inData, objs, prop, values) outData.objs = {inData.objs{:}, objs}; outData.prop = {inData.prop{:}, prop}; outData.values = {inData.values{:}, values}; function cellArray = LocalGetAsCell(fig,prop); cellArray = get(fig,prop); if (~isempty(cellArray)) & (~iscell(cellArray)) cellArray = {cellArray}; end function newArray = LocalScale(inArray, scale, minValue) n = length(inArray); newArray = cell(n,1); for k=1:n newArray{k} = max(minValue,scale*inArray{k}(1)); end function newArray = LocalMapToGray(inArray); n = length(inArray); newArray = cell(n,1); for k=1:n color = inArray{k}; if (~isempty(color)) if ischar(color) switch color(1) case 'y' color = [1 1 0]; case 'm' color = [1 0 1]; case 'c' color = [0 1 1]; case 'r' color = [1 0 0]; case 'g' color = [0 1 0]; case 'b' color = [0 0 1]; case 'w' color = [1 1 1]; case 'k' color = [0 0 0]; otherwise newArray{k} = color; end end if ~ischar(color) color = 0.30*color(1) + 0.59*color(2) + 0.11*color(3); end end if isempty(color) | ischar(color) newArray{k} = color; else newArray{k} = [color color color]; end end function newArray = LocalMapCData(inArray); n = length(inArray); newArray = cell(n,1); for k=1:n color = inArray{k}; if (ndims(color) == 3) & isa(color,'double') gray = 0.30*color(:,:,1) + 0.59*color(:,:,2) + 0.11*color(:,:,3); color(:,:,1) = gray; color(:,:,2) = gray; color(:,:,3) = gray; end newArray{k} = color; end function outData = LocalUpdateColors(inArray, prop, inData) value = LocalGetAsCell(inArray,prop); outData.objs = {inData.objs{:}, inArray}; outData.prop = {inData.prop{:}, {prop}}; outData.values = {inData.values{:}, value}; if (~isempty(value)) if strcmp(prop,'CData') value = LocalMapCData(value); else value = LocalMapToGray(value); end set(inArray,{prop},value); end function bool = LocalIsPositiveScalar(value) bool = isnumeric(value) & ... prod(size(value)) == 1 & ... value > 0; function value = LocalToNum(value) if ischar(value) value = str2num(value); end