/src/utils/exportfig.m
MATLAB | 500 lines | 364 code | 31 blank | 105 comment | 75 complexity | 3fb4cc687ce007f07fa078e88d2e0ab0 MD5 | raw file
Possible License(s): BSD-2-Clause
- 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