# imdisp

## PURPOSE

IMDISP Display one or more images nicely

## SYNOPSIS

function hIm = imdisp(I, varargin)

## DESCRIPTION

    IMDISP  Display one or more images nicely

     Examples:
       imdisp
       imdisp(I)
       imdisp(I, map)
       imdisp(I, lims)
       imdisp(I, map, lims)
       imdisp(..., param1, value1, param2, value2, ...)
       h = imdisp(...)

     This function displays one or more images nicely. Images can be defined
     by arrays or filenames. Multiple images can be input in a cell array or
     stacked along the fourth dimension, and are displayed as a grid of
     subplots (an improvement over MONTAGE). The size of grid is calculated or
     user defined. The figure size is set so that images are magnified by an
     integer value.

     If the image grid size is user defined, images not fitting in the grid
     can be scrolled through using the following key presses:
        Up - Back a row.
        Down - Forward a row.
        Left - Back a page (or column if there is only one row).
        Right - Forward a page (or column if there is only one row).
        Shift - 2 x speed.
        Ctrl - 4 x speed.
        Shift + Ctrl - 8 x speed.

     This allows fast scrolling through a movie or image stack, e.g.
        imdisp(imstack, 'Size', 1)
     The function can be used as a visual DIR, e.g.
        imdisp()
     to display all images in the current directory on a grid, or
        imdisp({}, 'Size', 1)
     to scroll through them one at a time.

     IN:
       I - MxNxCxP array of images, or 1xP cell array. C is 1 for indexed
           images or 3 for RGB images. P is the number of images. If I is a
           cell array then each cell must contain an image. Images can equally
           be defined by filenames. If I is an empty cell array then all the
           images in the current directory are used. Default: {}.
       map - Kx3 colormap to be used with indexed images. Default: gray(256).
       lims - [LOW HIGH] display range for indexed images. Default: [min(I(:))
              max(I(:))].
       Optional parameters - name, value parameter pairs for the following:
          'Size' - [H W] size of grid to display image on. If only H is given
                   then W = H. If either H or W is NaN then the number of rows
                   or columns is chosen such that all images fit. If both H
                   and W are NaN or the array is empty then the size of grid
                   is chosen to fit all images in as large as possible.
                   Default: [].
          'Indices' - 1xL list of indices of images to display. Default: 1:P.
          'Border' - [TB LR] borders to give each image top and bottom (TB)
                     and left and right (LR), to space out images. Borders are
                     normalized to the subplot size, i.e. TB = 0.01 gives a
                     border 1% of the height of each subplot. If only TB is
                     given, LR = TB. Default: 0.01.
          'DisplayRange' - Same as lims input.
          'Map' - Kx3 colormap or (additionally from above) name of MATLAB
                  colormap, for use with indexed images. Default: gray(256).

     OUT:
       h - HxW array of handles to images.

       See also IMAGE, IMAGESC, IMSHOW, MONTAGE.

## CROSS-REFERENCE INFORMATION

This function calls:

This function is called by:

## SUBFUNCTIONS

- function keypress_callback(fig, event_data)
- function hIm = display_image(A, hAx, lims)
- function layout = choose_layout(n, y, x, layout)
- function A = imread_rgb(name)
- function A = imread_rgb_multi(name)
- function L = get_im_names
- function [map layout gap indices lims] = parse_inputs(inputs)
- function lims = default_limits(A)
- function lims = min_max(A)

## SOURCE CODE

    0001 function hIm = imdisp(I, varargin)
    0002 %IMDISP  Display one or more images nicely
    0003 %
    0004 % Examples:
    0005 %   imdisp
    0006 %   imdisp(I)
    0007 %   imdisp(I, map)
    0008 %   imdisp(I, lims)
    0009 %   imdisp(I, map, lims)
    0010 %   imdisp(..., param1, value1, param2, value2, ...)
    0011 %   h = imdisp(...)
    0012 %
    0013 % This function displays one or more images nicely. Images can be defined
    0014 % by arrays or filenames. Multiple images can be input in a cell array or
    0015 % stacked along the fourth dimension, and are displayed as a grid of
    0016 % subplots (an improvement over MONTAGE). The size of grid is calculated or
    0017 % user defined. The figure size is set so that images are magnified by an
    0018 % integer value.
    0019 %
    0020 % If the image grid size is user defined, images not fitting in the grid
    0021 % can be scrolled through using the following key presses:
    0022 %    Up - Back a row.
    0023 %    Down - Forward a row.
    0024 %    Left - Back a page (or column if there is only one row).
    0025 %    Right - Forward a page (or column if there is only one row).
    0026 %    Shift - 2 x speed.
    0027 %    Ctrl - 4 x speed.
    0028 %    Shift + Ctrl - 8 x speed.
    0029 %
    0030 % This allows fast scrolling through a movie or image stack, e.g.
    0031 %    imdisp(imstack, 'Size', 1)
    0032 % The function can be used as a visual DIR, e.g.
    0033 %    imdisp()
    0034 % to display all images in the current directory on a grid, or
    0035 %    imdisp({}, 'Size', 1)
    0036 % to scroll through them one at a time.
    0037 %
    0038 % IN:
    0039 %   I - MxNxCxP array of images, or 1xP cell array. C is 1 for indexed
    0040 %       images or 3 for RGB images. P is the number of images. If I is a
    0041 %       cell array then each cell must contain an image. Images can equally
    0042 %       be defined by filenames. If I is an empty cell array then all the
    0043 %       images in the current directory are used. Default: {}.
    0044 %   map - Kx3 colormap to be used with indexed images. Default: gray(256).
    0045 %   lims - [LOW HIGH] display range for indexed images. Default: [min(I(:))
    0046 %          max(I(:))].
    0047 %   Optional parameters - name, value parameter pairs for the following:
    0048 %      'Size' - [H W] size of grid to display image on. If only H is given
    0049 %               then W = H. If either H or W is NaN then the number of rows
    0050 %               or columns is chosen such that all images fit. If both H
    0051 %               and W are NaN or the array is empty then the size of grid
    0052 %               is chosen to fit all images in as large as possible.
    0053 %               Default: [].
    0054 %      'Indices' - 1xL list of indices of images to display. Default: 1:P.
    0055 %      'Border' - [TB LR] borders to give each image top and bottom (TB)
    0056 %                 and left and right (LR), to space out images. Borders are
    0057 %                 normalized to the subplot size, i.e. TB = 0.01 gives a
    0058 %                 border 1% of the height of each subplot. If only TB is
    0059 %                 given, LR = TB. Default: 0.01.
    0060 %      'DisplayRange' - Same as lims input.
    0061 %      'Map' - Kx3 colormap or (additionally from above) name of MATLAB
    0062 %              colormap, for use with indexed images. Default: gray(256).
    0063 %
    0064 % OUT:
    0065 %   h - HxW array of handles to images.
    0066 %
    0067 %   See also IMAGE, IMAGESC, IMSHOW, MONTAGE.
    0068
    0069 % Parse inputs
    0070 [map layout gap indices lims] = parse_inputs(varargin);
    0071
    0072 if nargin == 0 || (iscell(I) && isempty(I))
    0073     % Read in all the images in the directory
    0074     I = get_im_names;
    0075     if isempty(I)
    0076         % No images found
    0077         if nargout > 0
    0078             hIm = [];
    0079         end
    0080         return
    0081     end
    0082 end
    0083
    0084 % Check if input is filenames
    0085 if ischar(I)
    0086     [x y c] = size(I);
    0087     if (x > 1 && y > 1) || c > 1
    0088         I = num2cell(I, 2);
    0089     else
    0090         I = {I(:)'};
    0091     end
    0092 end
    0093
    0094 % Get limits, etc.
    0095 if isnumeric(I) || islogical(I)
    0096     [y x c n] = size(I);
    0097     if isempty(lims)
    0098         lims = min_max(I);
    0099     elseif isequal(0, lims)
    0100         lims = default_limits(I);
    0101     elseif c == 3
    0102         % Rescale
    0103         if ~isfloat(I)
    0104             I = single(I);
    0105         end
    0106         I = min(max((I - lims(1)) ./ (lims(2) - lims(1)), 0), 1);
    0107     end
    0108     if isfloat(I) && c == 3 && n > 1
    0109         I = uint8(I * 256 - 0.5);
    0110         lims = round(lims * 256 - 0.5);
    0111     end
    0112 elseif iscell(I)
    0113     n = numel(I);
    0114     A = I{1};
    0115     if ischar(A)
    0116         % Read in the image (or images for multi-frame files)
    0117         if n == 1
    0118             I = imread_rgb_multi(A);
    0119             if iscell(I)
    0120                 n = numel(I);
    0121                 A = I{1};
    0122                 [y x c] = size(A);
    0123             else
    0124                 [y x c n] = size(I);
    0125                 A = I;
    0126             end
    0127         else
    0128             A = imread_rgb(A);
    0129             I{1} = A;
    0130             [y x c] = size(A);
    0131         end
    0132     else
    0133         [y x c] = size(A);
    0134     end
    0135     % Assume all images are the same size and type as the first
    0136     if isempty(lims) || isequal(0, lims)
    0137         lims = default_limits(A);
    0138     end
    0139 else
    0140     error('I not of recognized type.');
    0141 end
    0142
    0143 % Select indexed images
    0144 if ~isequal(indices, -1)
    0145     if iscell(I)
    0146         I = I(indices);
    0147         n = numel(I);
    0148     else
    0149         I = I(:,:,:,indices);
    0150         n = size(I, 4);
    0151     end
    0152 end
    0153
    0154 % Get the current figure
    0155 hFig = get(0, 'CurrentFigure');
    0156 if isempty(hFig)
    0157     % Create a new figure
    0158     hFig = figure;
    0159 elseif n > 1
    0160     % Clear the figure
    0161     hFig = clf(hFig, 'reset');
    0162 end
    0163
    0164 % Set the colormap
    0165 set(hFig, 'Colormap', map);
    0166
    0167 % Display the image(s)
    0168 if n == 0
    0169     hIm = display_image([], gca, [0 1]);
    0170
    0171     if nargout == 0
    0172         clear hIm % Avoid printing this out
    0173     end
    0174     return
    0175 elseif n == 1
    0176     % IMSHOW mode
    0177     % Display the single image
    0178     hAx = gca;
    0179     if iscell(I)
    0180         I = I{1};
    0181     end
    0182     hIm = display_image(I, hAx, lims);
    0183
    0184     if nargout == 0
    0185         clear hIm % Avoid printing this out
    0186     end
    0187
    0188     % Only resize image if it is alone in the figure
    0189     if numel(findobj(get(hFig, 'Children'), 'Type', 'axes')) > 1
    0190         return
    0191     end
    0192     % Could still be the first subplot - do another check
    0193     axesPos = get(hAx, 'Position');
    0194     newAxesPos = [gap(1) gap(end) 1-2*gap(1) 1-2*gap(end)];
    0195     if isequal(axesPos, get(hFig, 'DefaultAxesPosition'))
    0196         % Default position => not a subplot
    0197         % Fill the window
    0198         set(hAx, 'Units', 'normalized', 'Position', newAxesPos);
    0199         axesPos = newAxesPos;
    0200     end
    0201     if ~isequal(axesPos, newAxesPos)
    0202         % Figure not alone, so don't resize.
    0203         return
    0204     end
    0205     layout = [1 1];
    0206 else
    0207     % MONTAGE mode
    0208     % Compute a good layout
    0209     layout = choose_layout(n, y, x, layout);
    0210
    0211     % Create a data structure to store the data in
    0212     num = prod(layout);
    0213     state.num = num * ceil(n / num);
    0214     hIm = zeros(layout);
    0215     hAx = zeros(layout);
    0216
    0217     % Set the first lot of images
    0218     index = mod(0:num-1, state.num) + 1;
    0219     hw = 1 ./ layout;
    0220     gap = gap ./ layout;
    0221     dims = hw - 2 * gap;
    0222     dims = dims([2 1]);
    0223     for a = 1:layout(1)
    0224         for b = 1:layout(2)
    0225             c = index(b + (layout(1) - a) * layout(2));
    0226             if c > n
    0227                 A = [];
    0228             elseif iscell(I)
    0229                 A = I{c};
    0230                 if ischar(A)
    0231                     A = imread_rgb(A);
    0232                     I{c} = A;
    0233                 end
    0234             else
    0235                 A = I(:,:,:,c);
    0236             end
    0237             hAx(a,b) = axes('Position', [(b-1)*hw(2)+gap(2) (a-1)*hw(1)+gap(1) dims], 'Units', 'normalized');
    0238             hIm(a,b) = display_image(A, hAx(a,b), lims);
    0239         end
    0240     end
    0241
    0242     % Check if we need to be able to scroll through images
    0243     if n > num
    0244         % Intialize rest of data structure
    0245         state.hIm = hIm;
    0246         state.hAx = hAx;
    0247         state.index = 1;
    0248         state.layout = layout;
    0249         state.n = n;
    0250         state.I = I;
    0251         % Set the callback for image navigation, and save the image data in the figure
    0252         set(hFig, 'KeyPressFcn', @keypress_callback, 'Interruptible', 'off', 'BusyAction', 'cancel', 'UserData', state);
    0253     end
    0254
    0255     % Flip hIm so it matches the layout
    0256     hIm = hIm(end:-1:1,:);
    0257
    0258     if nargout == 0
    0259         clear hIm % Avoid printing this out
    0260     end
    0261 end
    0262
    0263 if strcmp(get(hFig, 'WindowStyle'), 'docked')
    0264     % Figure is docked, so can't resize
    0265     return
    0266 end
    0267
    0268 % Set the figure size well
    0269 % Compute the image size
    0270 ImSz = layout([2 1]) .* [x y] ./ (1 - 2 * gap([end 1]));
    0271
    0272 % Get the size of the monitor we're on
    0273 figPosCur = get(hFig, 'Position');
    0274 % Monitor sizes
    0275 MonSz = get(0, 'MonitorPositions');
    0276 MonOn = size(MonSz, 1);
    0277 if MonOn > 1
    0278     % Make the origin the top left corner of the primary monitor
    0279     correction = 0;
    0280     if ispc
    0281         for a = 1:MonOn
    0282             if isequal(MonSz(a,1:2), [1 1])
    0283                 correction = MonSz(a,4);
    0284                 break
    0285             end
    0286         end
    0287     end
    0288     % Determine which monitor the centre of the image is on
    0289     figCenter = figPosCur(1:2) + figPosCur(3:4) / 2;
    0290     figCenter = MonSz - repmat(figCenter, [MonOn 2]);
    0291     MonOn = all(sign(figCenter) == repmat([-1 -1 1 1], [MonOn 1]), 2);
    0292     MonOn(1) = MonOn(1) | ~any(MonOn);
    0293     MonSz = MonSz(MonOn,:);
    0294     % Correct the size
    0295     MonSz(3:4) = MonSz(3:4) - MonSz(1:2) + 1;
    0296     % Correct the origin
    0297     if correction
    0298         MonSz(2) = correction - MonSz(4) - MonSz(2) + 2;
    0299     end
    0300 end
    0301
    0302 % Check if the window is maximized
    0303 % This is a hack which may only work on Windows! No matter, though.
    0304 if isequal(MonSz([1 3]), figPosCur([1 3]))
    0305     % Leave maximized
    0306     return
    0307 end
    0308
    0309 % Compute the size to set the window
    0310 MaxSz = MonSz(3:4) - [20 120];
    0311 RescaleFactor = min(MaxSz ./ ImSz);
    0312 if RescaleFactor > 1
    0313     % Integer scale for enlarging, but don't make too big
    0314     MaxSz = min(MaxSz, [1200 800]);
    0315     RescaleFactor = max(floor(min(MaxSz ./ ImSz)), 1);
    0316 end
    0317 figPosNew = ceil(ImSz * RescaleFactor);
    0318
    0319 % Don't move the figure if the size isn't changing
    0320 if isequal(figPosCur(3:4), figPosNew)
    0321     return
    0322 end
    0323
    0324 % Keep the centre of the figure stationary
    0325 figPosNew = [floor(figPosCur(1:2)+(figPosCur(3:4)-figPosNew)/2) figPosNew];
    0326
    0327 % Ensure the figure is in bounds
    0328 figPosNew(1:2) = min(max(figPosNew(1:2), MonSz(1:2)+6), MonSz(1:2)+MonSz(3:4)-[6 101]-figPosNew(3:4));
    0329
    0330 % Set the figure size and position
    0331 set(hFig, 'Position', figPosNew);
    0332 return
    0333
    0334 %% Keypress callback
    0335 % The function which does all the display stuff
    0336 function keypress_callback(fig, event_data)
    0337 % Check what key was pressed and update the image index as necessary
    0338 switch event_data.Character
    0339     case 28 % Left
    0340         up = -1; % Back a page
    0341     case 29 % Right
    0342         up = 1; % Forward a page
    0343     case 30 % Up
    0344         up = -0.1; % Back a row
    0345     case 31 % Down
    0346         up = 0.1; % Forward a row
    0347     otherwise
    0348         % Another key was pressed - ignore it
    0349         return
    0350 end
    0351 % Use control and shift for faster scrolling
    0352 if ~isempty(event_data.Modifier)
    0353     up = up * (2 ^ (strcmpi(event_data.Modifier, {'shift', 'control'}) * [1; 2]));
    0354 end
    0355 % Get the state data
    0356 state = get(fig, 'UserData');
    0357 % Get the current index
    0358 index = state.index;
    0359 % Get number of images
    0360 n = prod(state.layout);
    0361 % Generate 12 valid indices
    0362 if abs(up) < 1
    0363     % Increment by row
    0364     index = index + state.layout(2) * (up * 10) - 1;
    0365 else
    0366     if state.layout(1) == 1
    0367         % Increment by column
    0368         index = index + up - 1;
    0369     else
    0370         % Increment by page
    0371         index = index + n * up - 1;
    0372     end
    0373 end
    0374 index = mod(index:index+n, state.num) + 1;
    0375 % Plot the images
    0376 figure(fig);
    0377 for a = 1:state.layout(1)
    0378     for b = 1:state.layout(2)
    0379         % Get the image
    0380         c = index(b + (state.layout(1) - a) * state.layout(2));
    0381         if c > state.n
    0382             % Set the image data
    0383             set(state.hIm(a,b), 'CData', []);
    0384         elseif iscell(state.I)
    0385             A = state.I{c};
    0386             if ischar(A)
    0387                 % Filename - read the image from disk
    0388                 A = imread_rgb(A);
    0389                 state.I{c} = A;
    0390             end
    0391             % Set the image data
    0392             set(state.hIm(a,b), 'CData', A);
    0393             % Reset the axes limits
    0394             if ~isempty(A)
    0395                 set(state.hAx(a,b), 'XLim', [0.5 size(A, 2)+0.5], 'YLim', [0.5 size(A, 1)+0.5]);
    0396             end
    0397         else
    0398             % Set the image data
    0399             set(state.hIm(a,b), 'CData', state.I(:,:,:,c));
    0400         end
    0401     end
    0402 end
    0403 drawnow;
    0404 % Save the current index
    0405 state.index = index(1);
    0406 set(fig, 'UserData', state);
    0407 return
    0408
    0409 %% Display the image
    0410 function hIm = display_image(A, hAx, lims)
    0411 if isempty(A)
    0412     hIm = image(zeros(1, 1, 3));
    0413     set(hIm, 'CData', []);
    0414 else
    0415     hIm = image(A);
    0416 end
    0417 set(hAx, 'Visible', 'off', 'DataAspectRatio', [1 1 1], 'DrawMode', 'fast', 'CLim', lims);
    0418 set(get(hAx, 'XLabel'), 'Visible', 'on');
    0419 set(get(hAx, 'YLabel'), 'Visible', 'on');
    0420 set(get(hAx, 'Title'), 'Visible', 'on');
    0421 set(hIm, 'CDataMapping', 'scaled');
    0422 return
    0423
    0424 %% Choose a good layout for the images
    0425 function layout = choose_layout(n, y, x, layout)
    0426 v = numel(layout);
    0427 N = isnan(layout);
    0428 if v == 0 || all(N)
    0429     % Compute approximate layout
    0430     sz = get(0, 'ScreenSize');
    0431     sz = sz(3:4) ./ [x y];
    0432     layout = ceil(sz([2 1]) ./ sqrt(prod(sz) / n));
    0433     % Remove superfluous rows or columns
    0434     while 1
    0435         switch ([prod(layout - [1 0]) prod(layout - [0 1])] >= n) * [2; 1]
    0436             case 0
    0437                 break;
    0438             case 1
    0439                 layout = layout - [0 1];
    0440             case 2
    0441                 layout = layout - [1 0];
    0442             case 3
    0443                 if min(sz .* (layout - [0 1])) > min(sz .* (layout - [1 0]))
    0444                     layout = layout - [0 1];
    0445                 else
    0446                     layout = layout - [1 0];
    0447                 end
    0448         end
    0449     end
    0450 elseif v == 1
    0451     layout = layout([1 1]);
    0452 elseif any(N)
    0453     layout(N) = ceil(n / layout(~N));
    0454 end
    0455 layout = reshape(layout, 1, 2);
    0456 return
    0457
    0458 %% Read image to uint8 rgb array
    0459 function A = imread_rgb(name)
    0460 try
    0461     [A map alpha] = imread(name);
    0462 catch
    0463     % Format not recognized by imread, so create a red cross (along diagonals)
    0464     A = eye(101) | diag(ones(100, 1), 1) | diag(ones(100, 1), -1);
    0465     A = (uint8(1) - uint8(A | flipud(A))) * uint8(255);
    0466     A = cat(3, zeros(size(A), 'uint8')+uint8(255), A, A);
    0467     return
    0468 end
    0469 A = A(:,:,:,1); % Keep only first frame of multi-frame files
    0470 if ~isempty(map)
    0471     map = uint8(map * 256 - 0.5); % Convert to uint8 for storage
    0472     A = reshape(map(uint32(A)+1,:), [size(A) size(map, 2)]); % Assume indexed from 0
    0473 elseif size(A, 3) == 4
    0474     if lower(name(end)) == 'f'
    0475         % TIFF in CMYK colourspace - convert to RGB
    0476         if isfloat(A)
    0477             A = A * 255;
    0478         else
    0479             A = single(A);
    0480         end
    0481         A = 255 - A;
    0482         A(:,:,4) = A(:,:,4) / 255;
    0483         A = uint8(A(:,:,1:3) .* A(:,:,[4 4 4]));
    0484     else
    0485         % Assume 4th channel is an alpha matte
    0486         alpha = A(:,:,4);
    0487         A = A(:,:,1:3);
    0488     end
    0489 end
    0490 if ~isempty(alpha)
    0491     % Apply transprency over a grey checkerboard pattern
    0492     if isa(alpha, 'uint8')
    0493         alpha = double(alpha) / 255;
    0494     end
    0495     A = double(A) .* alpha(:,:,ones(1, size(A, 3)));
    0496     sqSz = max(size(alpha));
    0497     sqSz = floor(max(log(sqSz / 100), 0) * 10 + 1 + min(sqSz, 100) / 20);
    0498     grid = repmat(85, ceil(size(alpha) / sqSz));
    0499     grid(2:2:end,1:2:end) = 171;
    0500     grid(1:2:end,2:2:end) = 171;
    0501     grid = kron(grid, ones(sqSz));
    0502     alpha = grid(1:size(A, 1),1:size(A, 2)) .* (1 - alpha);
    0503     A = uint8(A + alpha(:,:,ones(1, size(A, 3))));
    0504 end
    0505 return
    0506
    0507 %% Read (potentially) multi-frame image to uint8 rgb array
    0508 function A = imread_rgb_multi(name)
    0509 try
    0510     % Get file info
    0511     info = imfinfo(name);
    0512 catch
    0513     % Revert to standard case
    0514     A = imread_rgb(name);
    0515     return
    0516 end
    0517 if numel(info) < 2
    0518     % Single image
    0519     A = imread_rgb(name);
    0520     return
    0521 else
    0522     % Multi-frame image
    0523     switch lower(info(1).Format)
    0524         case 'gif'
    0525             [A map] = imread(name, 'frames', 'all');
    0526             if ~isempty(map)
    0527                 map = uint8(map * 256 - 0.5); % Convert to uint8 for storage
    0528                 A = reshape(map(uint32(A)+1,:), [size(A) size(map, 2)]); % Assume indexed from 0
    0529                 A = permute(A, [1 2 5 4 3]);
    0530             end
    0531         case {'tif', 'tiff'}
    0532             A = cell(numel(info), 1);
    0533             for a = 1:numel(A)
    0534                 [A{a} map] = imread(name, 'Index', a, 'Info', info);
    0535                 if ~isempty(map)
    0536                     map = uint8(map * 256 - 0.5); % Convert to uint8 for storage
    0537                     A{a} = reshape(map(uint32(A{a})+1,:), [size(A) size(map, 2)]); % Assume indexed from 0
    0538                 end
    0539                 if size(A{a}, 3) == 4
    0540                     % TIFF in CMYK colourspace - convert to RGB
    0541                     if isfloat(A{a})
    0542                         A{a} = A{a} * 255;
    0543                     else
    0544                         A{a} = single(A{a});
    0545                     end
    0546                     A{a} = 255 - A{a};
    0547                     A{a}(:,:,4) = A{a}(:,:,4) / 255;
    0548                     A{a} = uint8(A(:,:,1:3) .* A{a}(:,:,[4 4 4]));
    0549                 end
    0550             end
    0551         otherwise
    0552             % Multi-frame not supported for this format
    0553             A = imread_rgb(name);
    0554             return
    0555     end
    0556 end
    0557 return
    0558
    0559 %% Get the names of all images in a directory
    0560 function L = get_im_names
    0561 D = dir;
    0562 n = 0;
    0563 L = cell(size(D));
    0564 % Go through the directory list
    0565 for a = 1:numel(D)
    0566     % Check if file is a supported image type
    0567     if numel(D(a).name) > 4 && ~D(a).isdir && (any(strcmpi(D(a).name(end-3:end), {'.png', '.tif', '.jpg', '.bmp', '.ppm', '.pgm', '.pbm', '.gif', '.ras'})) || any(strcmpi(D(a).name(end-4:end), {'.tiff', '.jpeg'})))
    0568         n = n + 1;
    0569         L{n} = D(a).name;
    0570     end
    0571 end
    0572 L = L(1:n);
    0573 return
    0574
    0575 %% Parse inputs
    0576 function [map layout gap indices lims] = parse_inputs(inputs)
    0577
    0578 % Set defaults
    0579 map = [];
    0580 layout = [];
    0581 gap = 0;
    0582 indices = -1;
    0583 lims = 0;
    0584
    0585 % Check for map and display range
    0586 for b = 1:numel(inputs)
    0587     if ~isnumeric(inputs{b})
    0588         b = b - 1;
    0589         break;
    0590     end
    0591     if size(inputs{b}, 2) == 3
    0592         map = inputs{b};
    0593     elseif numel(inputs{b}) < 3
    0594         lims = inputs{b};
    0595     end
    0596 end
    0597
    0598 % Go through option pairs
    0599 for a = b+1:2:numel(inputs)
    0600     switch lower(inputs{a})
    0601         case 'map'
    0602             map = inputs{a+1};
    0603             if ischar(map)
    0604                 map = feval(map, 256);
    0605             end
    0606         case {'size', 'grid'}
    0607             layout = inputs{a+1};
    0608         case {'gap', 'border'}
    0609             gap = inputs{a+1};
    0610         case 'indices'
    0611             indices = inputs{a+1};
    0612         case {'lims', 'displayrange'}
    0613             lims = inputs{a+1};
    0614         otherwise
    0615             error('Input option %s not recognized', inputs{a});
    0616     end
    0617 end
    0618
    0619 if isempty(map)
    0620    map = gray(256);
    0621 end
    0622 return
    0623
    0624 %% Return default limits for the image type
    0625 function lims = default_limits(A)
    0626 if size(A, 3) == 1
    0627     lims = min_max(A);
    0628 else
    0629     lims = [0 1];
    0630     if ~isfloat(A)
    0631         lims = lims * double(intmax(class(A)));
    0632     end
    0633 end
    0634 return
    0635
    0636 %% Return minimum and maximum values
    0637 function lims = min_max(A)
    0638 M = isfinite(A);
    0639 lims = double([min(A(M)) max(A(M))]);
    0640 if isempty(lims)
    0641     lims = [0 1];
    0642 elseif lims(1) == lims(2)
    0643     lims(2) = lims(1) + 1;
    0644 end
    0645 return