Home | History | Annotate | Download | only in test_framework
      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