source: issm/trunk-jpl/externalpackages/export_fig/export_fig.m@ 12407

Last change on this file since 12407 was 12407, checked in by Mathieu Morlighem, 13 years ago

updated export_fig to newest version

File size: 28.8 KB
Line 
1%EXPORT_FIG Exports figures suitable for publication
2%
3% Examples:
4% im = export_fig
5% [im alpha] = export_fig
6% export_fig filename
7% export_fig filename -format1 -format2
8% export_fig ... -nocrop
9% export_fig ... -transparent
10% export_fig ... -native
11% export_fig ... -m<val>
12% export_fig ... -r<val>
13% export_fig ... -a<val>
14% export_fig ... -q<val>
15% export_fig ... -<renderer>
16% export_fig ... -<colorspace>
17% export_fig ... -append
18% export_fig ... -bookmark
19% export_fig(..., handle)
20%
21% This function saves a figure or single axes to one or more vector and/or
22% bitmap file formats, and/or outputs a rasterized version to the
23% workspace, with the following properties:
24% - Figure/axes reproduced as it appears on screen
25% - Cropped borders (optional)
26% - Embedded fonts (vector formats)
27% - Improved line and grid line styles
28% - Anti-aliased graphics (bitmap formats)
29% - Render images at native resolution (optional for bitmap formats)
30% - Transparent background supported (pdf, eps, png)
31% - Semi-transparent patch objects supported (png only)
32% - RGB, CMYK or grayscale output (CMYK only with pdf, eps, tiff)
33% - Variable image compression, including lossless (pdf, eps, jpg)
34% - Optionally append to file (pdf, tiff)
35% - Vector formats: pdf, eps
36% - Bitmap formats: png, tiff, jpg, bmp, export to workspace
37%
38% This function is especially suited to exporting figures for use in
39% publications and presentations, because of the high quality and
40% portability of media produced.
41%
42% Note that the background color and figure dimensions are reproduced
43% (the latter approximately, and ignoring cropping & magnification) in the
44% output file. For transparent background (and semi-transparent patch
45% objects), use the -transparent option or set the figure 'Color' property
46% to 'none'. To make axes transparent set the axes 'Color' property to
47% 'none'. Pdf, eps and png are the only file formats to support a
48% transparent background, whilst the png format alone supports transparency
49% of patch objects.
50%
51% The choice of renderer (opengl, zbuffer or painters) has a large impact
52% on the quality of output. Whilst the default value (opengl for bitmaps,
53% painters for vector formats) generally gives good results, if you aren't
54% satisfied then try another renderer. Notes: 1) For vector formats (eps,
55% pdf), only painters generates vector graphics. 2) For bitmaps, only
56% opengl can render transparent patch objects correctly. 3) For bitmaps,
57% only painters will correctly scale line dash and dot lengths when
58% magnifying or anti-aliasing. 4) Fonts may be substitued with Courier when
59% using painters.
60%
61% When exporting to vector format (pdf & eps) and bitmap format using the
62% painters renderer, this function requires that ghostscript is installed
63% on your system. You can download this from:
64% http://www.ghostscript.com
65% When exporting to eps it additionally requires pdftops, from the Xpdf
66% suite of functions. You can download this from:
67% http://www.foolabs.com/xpdf
68%
69%IN:
70% filename - string containing the name (optionally including full or
71% relative path) of the file the figure is to be saved as. If
72% a path is not specified, the figure is saved in the current
73% directory. If no name and no output arguments are specified,
74% the default name, 'export_fig_out', is used. If neither a
75% file extension nor a format are specified, a ".png" is added
76% and the figure saved in that format.
77% -format1, -format2, etc. - strings containing the extensions of the
78% file formats the figure is to be saved as.
79% Valid options are: '-pdf', '-eps', '-png',
80% '-tif', '-jpg' and '-bmp'. All combinations
81% of formats are valid.
82% -nocrop - option indicating that the borders of the output are not to
83% be cropped.
84% -transparent - option indicating that the figure background is to be
85% made transparent (png, pdf and eps output only).
86% -m<val> - option where val indicates the factor to magnify the
87% on-screen figure dimensions by when generating bitmap
88% outputs. Default: '-m1'.
89% -r<val> - option val indicates the resolution (in pixels per inch) to
90% export bitmap outputs at, keeping the dimensions of the
91% on-screen figure. Default: sprintf('-r%g', get(0,
92% 'ScreenPixelsPerInch')). Note that the -m and -r options
93% change the same property.
94% -native - option indicating that the output resolution (when outputting
95% a bitmap format) should be such that the vertical resolution
96% of the first suitable image found in the figure is at the
97% native resolution of that image. To specify a particular
98% image to use, give it the tag 'export_fig_native'. Notes:
99% This overrides any value set with the -m and -r options. It
100% also assumes that the image is displayed front-to-parallel
101% with the screen. The output resolution is approximate and
102% should not be relied upon. Anti-aliasing can have adverse
103% effects on image quality (disable with the -a1 option).
104% -a1, -a2, -a3, -a4 - option indicating the amount of anti-aliasing to
105% use for bitmap outputs. '-a1' means no anti-
106% aliasing; '-a4' is the maximum amount (default).
107% -<renderer> - option to force a particular renderer (painters, opengl
108% or zbuffer) to be used over the default: opengl for
109% bitmaps; painters for vector formats.
110% -<colorspace> - option indicating which colorspace color figures should
111% be saved in: RGB (default), CMYK or gray. CMYK is only
112% supported in pdf, eps and tiff output.
113% -q<val> - option to vary bitmap image quality (in pdf, eps and jpg
114% files only). Larger val, in the range 0-100, gives higher
115% quality/lower compression. val > 100 gives lossless
116% compression. Default: '-q95' for jpg, ghostscript prepress
117% default for pdf & eps. Note: lossless compression can
118% sometimes give a smaller file size than the default lossy
119% compression, depending on the type of images.
120% -append - option indicating that if the file (pdfs only) already
121% exists, the figure is to be appended as a new page, instead
122% of being overwritten (default).
123% -bookmark - option to indicate that a bookmark with the name of the
124% figure is to be created in the output file (pdf only).
125% handle - The handle of the figure or axes (can be an array of handles
126% of several axes, but these must be in the same figure) to be
127% saved. Default: gcf.
128%
129%OUT:
130% im - MxNxC uint8 image array of the figure.
131% alpha - MxN single array of alphamatte values in range [0,1], for the
132% case when the background is transparent.
133%
134% Some helpful examples and tips can be found at:
135% http://sites.google.com/site/oliverwoodford/software/export_fig
136%
137% See also PRINT, SAVEAS.
138
139% Copyright (C) Oliver Woodford 2008-2012
140
141% The idea of using ghostscript is inspired by Peder Axensten's SAVEFIG
142% (fex id: 10889) which is itself inspired by EPS2PDF (fex id: 5782).
143% The idea for using pdftops came from the MATLAB newsgroup (id: 168171).
144% The idea of editing the EPS file to change line styles comes from Jiro
145% Doke's FIXPSLINESTYLE (fex id: 17928).
146% The idea of changing dash length with line width came from comments on
147% fex id: 5743, but the implementation is mine :)
148% The idea of anti-aliasing bitmaps came from Anders Brun's MYAA (fex id:
149% 20979).
150% The idea of appending figures in pdfs came from Matt C in comments on the
151% FEX (id: 23629)
152
153% Thanks to Roland Martin for pointing out the colour MATLAB
154% bug/feature with colorbar axes and transparent backgrounds.
155% Thanks also to Andrew Matthews for describing a bug to do with the figure
156% size changing in -nodisplay mode. I couldn't reproduce it, but included a
157% fix anyway.
158% Thanks to Tammy Threadgill for reporting a bug where an axes is not
159% isolated from gui objects.
160
161% 23/02/12: Ensure that axes limits don't change during printing
162% 14/03/12: Fix bug in fixing the axes limits (thanks to Tobias Lamour for
163% reporting it).
164% 02/05/12: Incorporate patch of Petr Nechaev (many thanks), enabling
165% bookmarking of figures in pdf files.
166% 09/05/12: Incorporate patch of Arcelia Arrieta (many thanks), to keep
167% tick marks fixed.
168
169function [im alpha] = export_fig(varargin)
170% Make sure the figure is rendered correctly _now_ so that properties like
171% axes limits are up-to-date.
172drawnow;
173% Parse the input arguments
174[fig options] = parse_args(nargout, varargin{:});
175% Isolate the subplot, if it is one
176cls = strcmp(get(fig(1), 'Type'), 'axes');
177if cls
178 % Given handles of one or more axes, so isolate them from the rest
179 fig = isolate_axes(fig);
180else
181 old_mode = get(fig, 'InvertHardcopy');
182end
183% Hack the font units where necessary (due to a font rendering bug in
184% print?). This may not work perfectly in all cases. Also it can change the
185% figure layout if reverted, so use a copy.
186magnify = options.magnify * options.aa_factor;
187if isbitmap(options) && magnify ~= 1
188 fontu = findobj(fig, 'FontUnits', 'normalized');
189 if ~isempty(fontu)
190 % Some normalized font units found
191 if ~cls
192 fig = copyfig(fig);
193 set(fig, 'Visible', 'off');
194 fontu = findobj(fig, 'FontUnits', 'normalized');
195 cls = true;
196 end
197 set(fontu, 'FontUnits', 'points');
198 end
199end
200% MATLAB "feature": axes limits can change when printing
201Hlims = findall(fig, 'Type', 'axes');
202if ~cls
203 % Record the old axes limit and tick modes
204 Xlims = make_cell(get(Hlims, 'XLimMode'));
205 Ylims = make_cell(get(Hlims, 'YLimMode'));
206 Zlims = make_cell(get(Hlims, 'ZLimMode'));
207 Xtick = make_cell(get(Hlims, 'XTickMode'));
208 Ytick = make_cell(get(Hlims, 'YTickMode'));
209 Ztick = make_cell(get(Hlims, 'ZTickMode'));
210end
211% Set all axes limit and tick modes to manual, so the limits and ticks can't change
212set(Hlims, 'XLimMode', 'manual', 'YLimMode', 'manual', 'ZLimMode', 'manual', 'XTickMode', 'manual', 'YTickMode', 'manual', 'ZTickMode', 'manual');
213% Set to print exactly what is there
214set(fig, 'InvertHardcopy', 'off');
215% Set the renderer
216switch options.renderer
217 case 1
218 renderer = '-opengl';
219 case 2
220 renderer = '-zbuffer';
221 case 3
222 renderer = '-painters';
223 otherwise
224 renderer = '-opengl'; % Default for bitmaps
225end
226% Do the bitmap formats first
227if isbitmap(options)
228 % Get the background colour
229 if options.transparent && (options.png || options.alpha)
230 % Get out an alpha channel
231 % MATLAB "feature": black colorbar axes can change to white and vice versa!
232 hCB = findobj(fig, 'Type', 'axes', 'Tag', 'Colorbar');
233 if isempty(hCB)
234 yCol = [];
235 xCol = [];
236 else
237 yCol = get(hCB, 'YColor');
238 xCol = get(hCB, 'XColor');
239 if iscell(yCol)
240 yCol = cell2mat(yCol);
241 xCol = cell2mat(xCol);
242 end
243 yCol = sum(yCol, 2);
244 xCol = sum(xCol, 2);
245 end
246 % MATLAB "feature": apparently figure size can change when changing
247 % colour in -nodisplay mode
248 pos = get(fig, 'Position');
249 % Set the background colour to black, and set size in case it was
250 % changed internally
251 tcol = get(fig, 'Color');
252 set(fig, 'Color', 'k', 'Position', pos);
253 % Correct the colorbar axes colours
254 set(hCB(yCol==0), 'YColor', [0 0 0]);
255 set(hCB(xCol==0), 'XColor', [0 0 0]);
256 % Print large version to array
257 B = print2array(fig, magnify, renderer);
258 % Downscale the image
259 B = downsize(single(B), options.aa_factor);
260 % Set background to white (and set size)
261 set(fig, 'Color', 'w', 'Position', pos);
262 % Correct the colorbar axes colours
263 set(hCB(yCol==3), 'YColor', [1 1 1]);
264 set(hCB(xCol==3), 'XColor', [1 1 1]);
265 % Print large version to array
266 A = print2array(fig, magnify, renderer);
267 % Downscale the image
268 A = downsize(single(A), options.aa_factor);
269 % Set the background colour (and size) back to normal
270 set(fig, 'Color', tcol, 'Position', pos);
271 % Compute the alpha map
272 alpha = round(sum(B - A, 3)) / (255 * 3) + 1;
273 A = alpha;
274 A(A==0) = 1;
275 A = B ./ A(:,:,[1 1 1]);
276 clear B
277 % Convert to greyscale
278 if options.colourspace == 2
279 A = rgb2grey(A);
280 end
281 A = uint8(A);
282 % Crop the background
283 if options.crop
284 [alpha v] = crop_background(alpha, 0);
285 A = A(v(1):v(2),v(3):v(4),:);
286 end
287 if options.png
288 % Compute the resolution
289 res = options.magnify * get(0, 'ScreenPixelsPerInch') / 25.4e-3;
290 % Save the png
291 imwrite(A, [options.name '.png'], 'Alpha', alpha, 'ResolutionUnit', 'meter', 'XResolution', res, 'YResolution', res);
292 % Clear the png bit
293 options.png = false;
294 end
295 % Return only one channel for greyscale
296 if isbitmap(options)
297 A = check_greyscale(A);
298 end
299 if options.alpha
300 % Store the image
301 im = A;
302 % Clear the alpha bit
303 options.alpha = false;
304 end
305 % Get the non-alpha image
306 if isbitmap(options)
307 alph = alpha(:,:,ones(1, size(A, 3)));
308 A = uint8(single(A) .* alph + 255 * (1 - alph));
309 clear alph
310 end
311 if options.im
312 % Store the new image
313 im = A;
314 end
315 else
316 % Print large version to array
317 if options.transparent
318 % MATLAB "feature": apparently figure size can change when changing
319 % colour in -nodisplay mode
320 pos = get(fig, 'Position');
321 tcol = get(fig, 'Color');
322 set(fig, 'Color', 'w', 'Position', pos);
323 A = print2array(fig, magnify, renderer);
324 set(fig, 'Color', tcol, 'Position', pos);
325 tcol = 255;
326 else
327 [A tcol] = print2array(fig, magnify, renderer);
328 end
329 % Crop the background
330 if options.crop
331 A = crop_background(A, tcol);
332 end
333 % Downscale the image
334 A = downsize(A, options.aa_factor);
335 if options.colourspace == 2
336 % Convert to greyscale
337 A = rgb2grey(A);
338 else
339 % Return only one channel for greyscale
340 A = check_greyscale(A);
341 end
342 % Outputs
343 if options.im
344 im = A;
345 end
346 if options.alpha
347 im = A;
348 alpha = zeros(size(A, 1), size(A, 2), 'single');
349 end
350 end
351 % Save the images
352 if options.png
353 res = options.magnify * get(0, 'ScreenPixelsPerInch') / 25.4e-3;
354 imwrite(A, [options.name '.png'], 'ResolutionUnit', 'meter', 'XResolution', res, 'YResolution', res);
355 end
356 if options.bmp
357 imwrite(A, [options.name '.bmp']);
358 end
359 % Save jpeg with given quality
360 if options.jpg
361 quality = options.quality;
362 if isempty(quality)
363 quality = 95;
364 end
365 if quality > 100
366 imwrite(A, [options.name '.jpg'], 'Mode', 'lossless');
367 else
368 imwrite(A, [options.name '.jpg'], 'Quality', quality);
369 end
370 end
371 % Save tif images in cmyk if wanted (and possible)
372 if options.tif
373 if options.colourspace == 1 && size(A, 3) == 3
374 A = double(255 - A);
375 K = min(A, [], 3);
376 K_ = 255 ./ max(255 - K, 1);
377 C = (A(:,:,1) - K) .* K_;
378 M = (A(:,:,2) - K) .* K_;
379 Y = (A(:,:,3) - K) .* K_;
380 A = uint8(cat(3, C, M, Y, K));
381 clear C M Y K K_
382 end
383 append_mode = {'overwrite', 'append'};
384 imwrite(A, [options.name '.tif'], 'Resolution', options.magnify*get(0, 'ScreenPixelsPerInch'), 'WriteMode', append_mode{options.append+1});
385 end
386end
387% Now do the vector formats
388if isvector(options)
389 % Set the default renderer to painters
390 if ~options.renderer
391 renderer = '-painters';
392 end
393 % Generate some filenames
394 tmp_nam = [tempname '.eps'];
395 if options.pdf
396 pdf_nam = [options.name '.pdf'];
397 else
398 pdf_nam = [tempname '.pdf'];
399 end
400 % Generate the options for print
401 p2eArgs = {renderer};
402 if options.colourspace == 1
403 p2eArgs = [p2eArgs {'-cmyk'}];
404 end
405 if ~options.crop
406 p2eArgs = [p2eArgs {'-loose'}];
407 end
408 try
409 % Generate an eps
410 print2eps(tmp_nam, fig, p2eArgs{:});
411 % Remove the background, if desired
412 if options.transparent && ~isequal(get(fig, 'Color'), 'none')
413 eps_remove_background(tmp_nam);
414 end
415 % Add a bookmark to the PDF if desired
416 if options.bookmark
417 fig_nam = get(fig, 'Name');
418 if isempty(fig_nam)
419 warning('export_fig:EmptyBookmark', 'Bookmark requested for figure with no name. Bookmark will be empty.');
420 end
421 add_bookmark(tmp_nam, fig_nam);
422 end
423 % Generate a pdf
424 eps2pdf(tmp_nam, pdf_nam, 1, options.append, options.colourspace==2, options.quality);
425 catch ex
426 % Delete the eps
427 delete(tmp_nam);
428 rethrow(ex);
429 end
430 % Delete the eps
431 delete(tmp_nam);
432 if options.eps
433 try
434 % Generate an eps from the pdf
435 pdf2eps(pdf_nam, [options.name '.eps']);
436 catch ex
437 if ~options.pdf
438 % Delete the pdf
439 delete(pdf_nam);
440 end
441 rethrow(ex);
442 end
443 if ~options.pdf
444 % Delete the pdf
445 delete(pdf_nam);
446 end
447 end
448end
449if cls
450 % Close the created figure
451 close(fig);
452else
453 % Reset the hardcopy mode
454 set(fig, 'InvertHardcopy', old_mode);
455 % Reset the axes limit and tick modes
456 for a = 1:numel(Hlims)
457 set(Hlims(a), 'XLimMode', Xlims{a}, 'YLimMode', Ylims{a}, 'ZLimMode', Zlims{a}, 'XTickMode', Xtick{a}, 'YTickMode', Ytick{a}, 'ZTickMode', Ztick{a});
458 end
459end
460return
461
462function [fig options] = parse_args(nout, varargin)
463% Parse the input arguments
464% Set the defaults
465fig = get(0, 'CurrentFigure');
466options = struct('name', 'export_fig_out', ...
467 'crop', true, ...
468 'transparent', false, ...
469 'renderer', 0, ... % 0: default, 1: OpenGL, 2: ZBuffer, 3: Painters
470 'pdf', false, ...
471 'eps', false, ...
472 'png', false, ...
473 'tif', false, ...
474 'jpg', false, ...
475 'bmp', false, ...
476 'colourspace', 0, ... % 0: RGB/gray, 1: CMYK, 2: gray
477 'append', false, ...
478 'im', nout == 1, ...
479 'alpha', nout == 2, ...
480 'aa_factor', 3, ...
481 'magnify', 1, ...
482 'bookmark', false, ...
483 'quality', []);
484native = false; % Set resolution to native of an image
485
486% Go through the other arguments
487for a = 1:nargin-1
488 if all(ishandle(varargin{a}))
489 fig = varargin{a};
490 elseif ischar(varargin{a}) && ~isempty(varargin{a})
491 if varargin{a}(1) == '-'
492 switch lower(varargin{a}(2:end))
493 case 'nocrop'
494 options.crop = false;
495 case {'trans', 'transparent'}
496 options.transparent = true;
497 case 'opengl'
498 options.renderer = 1;
499 case 'zbuffer'
500 options.renderer = 2;
501 case 'painters'
502 options.renderer = 3;
503 case 'pdf'
504 options.pdf = true;
505 case 'eps'
506 options.eps = true;
507 case 'png'
508 options.png = true;
509 case {'tif', 'tiff'}
510 options.tif = true;
511 case {'jpg', 'jpeg'}
512 options.jpg = true;
513 case 'bmp'
514 options.bmp = true;
515 case 'rgb'
516 options.colourspace = 0;
517 case 'cmyk'
518 options.colourspace = 1;
519 case {'gray', 'grey'}
520 options.colourspace = 2;
521 case {'a1', 'a2', 'a3', 'a4'}
522 options.aa_factor = str2double(varargin{a}(3));
523 case 'append'
524 options.append = true;
525 case 'bookmark'
526 options.bookmark = true;
527 case 'native'
528 native = true;
529 otherwise
530 val = str2double(regexp(varargin{a}, '(?<=-(m|M|r|R|q|Q))(\d*\.)?\d+(e-?\d+)?', 'match'));
531 if ~isscalar(val)
532 error('option %s not recognised', varargin{a});
533 end
534 switch lower(varargin{a}(2))
535 case 'm'
536 options.magnify = val;
537 case 'r'
538 options.magnify = val ./ get(0, 'ScreenPixelsPerInch');
539 case 'q'
540 options.quality = max(val, 0);
541 end
542 end
543 else
544 [p options.name ext] = fileparts(varargin{a});
545 if ~isempty(p)
546 options.name = [p filesep options.name];
547 end
548 switch lower(ext)
549 case {'.tif', '.tiff'}
550 options.tif = true;
551 case {'.jpg', '.jpeg'}
552 options.jpg = true;
553 case '.png'
554 options.png = true;
555 case '.bmp'
556 options.bmp = true;
557 case '.eps'
558 options.eps = true;
559 case '.pdf'
560 options.pdf = true;
561 otherwise
562 options.name = varargin{a};
563 end
564 end
565 end
566end
567
568% Check we have a figure handle
569if isempty(fig)
570 error('No figure found');
571end
572
573% Set the default format
574if ~isvector(options) && ~isbitmap(options)
575 options.png = true;
576end
577
578% Check whether transparent background is wanted (old way)
579if isequal(get(fig, 'Color'), 'none')
580 options.transparent = true;
581end
582
583% If requested, set the resolution to the native vertical resolution of the
584% first suitable image found
585if native && isbitmap(options)
586 % Find a suitable image
587 list = findobj(fig, 'Type', 'image', 'Tag', 'export_fig_native');
588 if isempty(list)
589 list = findobj(fig, 'Type', 'image', 'Visible', 'on');
590 end
591 for hIm = list(:)'
592 % Check height is >= 2
593 height = size(get(hIm, 'CData'), 1);
594 if height < 2
595 continue
596 end
597 % Account for the image filling only part of the axes, or vice
598 % versa
599 yl = get(hIm, 'YData');
600 if isscalar(yl)
601 yl = [yl(1)-0.5 yl(1)+height+0.5];
602 else
603 if ~diff(yl)
604 continue
605 end
606 yl = yl + [-0.5 0.5] * (diff(yl) / (height - 1));
607 end
608 hAx = get(hIm, 'Parent');
609 yl2 = get(hAx, 'YLim');
610 % Find the pixel height of the axes
611 oldUnits = get(hAx, 'Units');
612 set(hAx, 'Units', 'pixels');
613 pos = get(hAx, 'Position');
614 set(hAx, 'Units', oldUnits);
615 if ~pos(4)
616 continue
617 end
618 % Found a suitable image
619 % Account for stretch-to-fill being disabled
620 pbar = get(hAx, 'PlotBoxAspectRatio');
621 pos = min(pos(4), pbar(2)*pos(3)/pbar(1));
622 % Set the magnification to give native resolution
623 options.magnify = (height * diff(yl2)) / (pos * diff(yl));
624 break
625 end
626end
627return
628
629function A = downsize(A, factor)
630% Downsample an image
631if factor == 1
632 % Nothing to do
633 return
634end
635try
636 % Faster, but requires image processing toolbox
637 A = imresize(A, 1/factor, 'bilinear');
638catch
639 % No image processing toolbox - resize manually
640 % Lowpass filter - use Gaussian as is separable, so faster
641 % Compute the 1d Gaussian filter
642 filt = (-factor-1:factor+1) / (factor * 0.6);
643 filt = exp(-filt .* filt);
644 % Normalize the filter
645 filt = single(filt / sum(filt));
646 % Filter the image
647 padding = floor(numel(filt) / 2);
648 for a = 1:size(A, 3)
649 A(:,:,a) = conv2(filt, filt', single(A([ones(1, padding) 1:end repmat(end, 1, padding)],[ones(1, padding) 1:end repmat(end, 1, padding)],a)), 'valid');
650 end
651 % Subsample
652 A = A(1+floor(mod(end-1, factor)/2):factor:end,1+floor(mod(end-1, factor)/2):factor:end,:);
653end
654return
655
656function A = rgb2grey(A)
657A = cast(reshape(reshape(single(A), [], 3) * single([0.299; 0.587; 0.114]), size(A, 1), size(A, 2)), class(A));
658return
659
660function A = check_greyscale(A)
661% Check if the image is greyscale
662if size(A, 3) == 3 && ...
663 all(reshape(A(:,:,1) == A(:,:,2), [], 1)) && ...
664 all(reshape(A(:,:,2) == A(:,:,3), [], 1))
665 A = A(:,:,1); % Save only one channel for 8-bit output
666end
667return
668
669function [A v] = crop_background(A, bcol)
670% Map the foreground pixels
671[h w c] = size(A);
672if isscalar(bcol) && c > 1
673 bcol = bcol(ones(1, c));
674end
675bail = false;
676for l = 1:w
677 for a = 1:c
678 if ~all(A(:,l,a) == bcol(a))
679 bail = true;
680 break;
681 end
682 end
683 if bail
684 break;
685 end
686end
687bail = false;
688for r = w:-1:l
689 for a = 1:c
690 if ~all(A(:,r,a) == bcol(a))
691 bail = true;
692 break;
693 end
694 end
695 if bail
696 break;
697 end
698end
699bail = false;
700for t = 1:h
701 for a = 1:c
702 if ~all(A(t,:,a) == bcol(a))
703 bail = true;
704 break;
705 end
706 end
707 if bail
708 break;
709 end
710end
711bail = false;
712for b = h:-1:t
713 for a = 1:c
714 if ~all(A(b,:,a) == bcol(a))
715 bail = true;
716 break;
717 end
718 end
719 if bail
720 break;
721 end
722end
723% Crop the background, leaving one boundary pixel to avoid bleeding on
724% resize
725v = [max(t-1, 1) min(b+1, h) max(l-1, 1) min(r+1, w)];
726A = A(v(1):v(2),v(3):v(4),:);
727return
728
729function eps_remove_background(fname)
730% Remove the background of an eps file
731% Open the file
732fh = fopen(fname, 'r+');
733if fh == -1
734 error('Not able to open file %s.', fname);
735end
736% Read the file line by line
737while true
738 % Get the next line
739 l = fgets(fh);
740 if isequal(l, -1)
741 break; % Quit, no rectangle found
742 end
743 % Check if the line contains the background rectangle
744 if isequal(regexp(l, ' *0 +0 +\d+ +\d+ +rf *[\n\r]+', 'start'), 1)
745 % Set the line to whitespace and quit
746 l(1:regexp(l, '[\n\r]', 'start', 'once')-1) = ' ';
747 fseek(fh, -numel(l), 0);
748 fprintf(fh, l);
749 break;
750 end
751end
752% Close the file
753fclose(fh);
754return
755
756function b = isvector(options)
757b = options.pdf || options.eps;
758return
759
760function b = isbitmap(options)
761b = options.png || options.tif || options.jpg || options.bmp || options.im || options.alpha;
762return
763
764% Helper function
765function A = make_cell(A)
766if ~iscell(A)
767 A = {A};
768end
769return
770
771function add_bookmark(fname, bookmark_text)
772% Adds a bookmark to the temporary EPS file after %%EndPageSetup
773% Read in the file
774fh = fopen(fname, 'r');
775if fh == -1
776 error('File %s not found.', fname);
777end
778try
779 fstrm = fread(fh, '*char')';
780catch ex
781 fclose(fh);
782 rethrow(ex);
783end
784fclose(fh);
785
786% Include standard pdfmark prolog to maximize compatibility
787fstrm = strrep(fstrm, '%%BeginProlog', sprintf('%%%%BeginProlog\n/pdfmark where {pop} {userdict /pdfmark /cleartomark load put} ifelse'));
788% Add page bookmark
789fstrm = strrep(fstrm, '%%EndPageSetup', sprintf('%%%%EndPageSetup\n[ /Title (%s) /OUT pdfmark',bookmark_text));
790
791% Write out the updated file
792fh = fopen(fname, 'w');
793if fh == -1
794 error('Unable to open %s for writing.', fname);
795end
796try
797 fwrite(fh, fstrm, 'char*1');
798catch ex
799 fclose(fh);
800 rethrow(ex);
801end
802fclose(fh);
803return
Note: See TracBrowser for help on using the repository browser.