function [X, map, alpha] = imread(varargin)
%IMREAD Read image from graphics file.
%   A = IMREAD(FILENAME,FMT) reads the image in FILENAME into
%   A. If the file contains a grayscale intensity image, A is
%   a two-dimensional array.  If the file contains a truecolor
%   (RGB) image, A is a three-dimensional (M-by-N-by-3) array.
%   FILENAME is a string that specifies the name of the
%   graphics file, and FMT is a string that specifies the
%   format of the file.  The file must be in the current
%   directory or in a directory on the MATLAB path.  If IMREAD
%   cannot find a file named FILENAME, it looks for a file
%   named FILENAME.FMT.
%
%   The possible values for FMT include:
%
%      'jpg' or 'jpeg' Joint Photographic Experts Group (JPEG)
%      'tif' or 'tiff' Tagged Image File Format (TIFF)
%      'gif'           Graphics Interchange Format (GIF)
%      'bmp'           Windows Bitmap (BMP)
%      'png'           Portable Network Graphics
%      'hdf'           Hierarchical Data Format (HDF)
%      'pcx'           Windows Paintbrush (PCX)
%      'xwd'           X Window Dump (XWD)
%      'cur'           Windows Cursor resources (CUR)
%      'ico'           Windows Icon resources (ICO)
%
%   [X,MAP] = IMREAD(FILENAME,FMT) reads the indexed image in
%   FILENAME into X and its associated colormap into MAP.
%   Colormap values in the image file are automatically
%   rescaled into the range [0,1]. 
%
%   [...] = IMREAD(FILENAME) attempts to infer the format of the
%   file from its content.
%
%   Data types
%   ----------
%   In most of the image file formats supported by IMREAD,
%   pixels are stored using 8 or fewer bits per color plane.
%   When reading such a file, the class of the output (A or X)
%   is uint8.  IMREAD also supports reading 16-bit-per-pixel
%   data from TIFF and PNG files; for such image files, the
%   class of the output (A or X) is uint16.
%
%   TIFF-specific syntaxes
%   ----------------------
%   [...] = IMREAD(...,IDX) reads in one image from a
%   multi-image TIFF file.  IDX is an integer value that
%   specifies the order that the image appears in the file.
%   For example, if IDX is 3, IMREAD reads the third image in
%   the file.  If you omit this argument, IMREAD reads the
%   first image in the file. 
%
%   PNG-specific syntaxes
%   ---------------------
%   [...] = IMREAD(...,'BackgroundColor',BG) composites any
%   transparent pixels in the input image against the color
%   specified in BG.  If BG is 'none', then no compositing is
%   performed. Otherwise, if the input image is indexed, BG
%   should be an integer in the range [1,P] where P is the
%   colormap length. If the input image is grayscale, BG
%   should be an integer in the range [0,1].  If the input
%   image is RGB, BG should be a three-element vector whose
%   values are in the range [0,1]. The string
%   'BackgroundColor' may be abbreviated.  
%
%   If the ALPHA output argument is used (see below), then BG
%   defaults to 'none' if not specified by the
%   user. Otherwise, if the PNG file contains a background
%   color chunk, that color is used as the default value for
%   BG. If ALPHA is not used and the file does not contain a
%   background color chunk, then the default value for BG is 1
%   for indexed images; 0 for grayscale images; and [0 0 0]
%   for RGB images.  
%
%   [A,MAP,ALPHA] = IMREAD(...) returns the alpha channel if
%   one is present; otherwise ALPHA is [].  Note that MAP may
%   be empty if the file contains a grayscale or truecolor 
%   image.
%
%   HDF-specific syntaxes
%   ---------------------
%   [...] = IMREAD(...,REF) reads in one image from a
%   multi-image HDF file.  REF is an integer value that
%   specifies the reference number used to identify the image.
%   For example, if REF is 12, IMREAD reads the image whose
%   reference number is 12.  (Note that in an HDF file the
%   reference numbers do not necessarily correspond with the
%   order of the images in the file.  You can use IMFINFO to
%   match up image order with reference number.)  If you omit
%   this argument, IMREAD reads the first image in the file.
%
%   ICO- and CUR-specific syntaxes
%   ------------------------------
%   [...] = IMREAD(...,IDX) reads in one image from a
%   multi-image icon or cursor file.  IDX is an integer value
%   that specifies the order that the image appears in the file.
%   For example, if IDX is 3, IMREAD reads the third image in
%   the file.  If you omit this argument, IMREAD reads the
%   first image in the file. 
%
%   [A,MAP,ALPHA] = IMREAD(...) returns the AND mask for the
%   resource, which can be used to determine the transparency
%   information.  For cursor files, this mask may contain the
%   only useful data.
%
%   Supported file types
%   --------------------
%   JPEG  Any baseline JPEG image; JPEG images with some
%         commonly used extensions
%
%   TIFF  Any baseline TIFF image, including 1-bit, 8-bit, and
%         24-bit uncompressed images; 1-bit, 8-bit, and 24-bit
%         images with packbits compression; 1-bit images with
%         CCITT compression; also, 16-bit grayscale, 16-bit
%         indexed, and 48-bit RGB images
%
%   GIF   Any 1-bit to 8-bit GIF image
%
%   BMP   1-bit, 4-bit, 8-bit, 24-bit, and 32-bit uncompressed images;
%         4-bit and 8-bit run-length encoded (RLE) images
%
%   PNG   Any PNG image, including 1-bit, 2-bit, 4-bit, 8-bit,
%         and 16-bit grayscale images; 8-bit and 16-bit
%         indexed images; 24-bit and 48-bit RGB images
%
%   HDF   8-bit raster image datasets, with or without an
%         associated colormap; 24-bit raster image datasets
%
%   PCX   1-bit, 8-bit, and 24-bit images
%
%   XWD   1-bit and 8-bit ZPixmaps; XYBitmaps; 1-bit XYPixmaps
%
%   ICO   1-bit, 4-bit, and 8-bit uncompressed images
%
%   CUR   1-bit, 4-bit, and 8-bit uncompressed images
%
%   See also IMFINFO, IMWRITE, FREAD, IMAGE, DOUBLE, UINT8.

%   Steven L. Eddins, June 1996
%   Copyright 1984-2000 The MathWorks, Inc.
%   $Revision: 1.21 $  $Date: 2000/06/01 04:17:45 $

[filename, format, extraArgs, msg] = parse_inputs(varargin{:});
if (~isempty(msg))
    error(msg);
end

%
% Open the file and determine/verify its format
%
if (isempty(format))
    % The format wasn't specified explicitly

    fid = fopen(filename, 'r');
    if (fid == -1)
        error(sprintf('Can''t open file "%s" for reading;\n it may not exist, or you may not have read permission.', ...
                      filename));
    else
        filename = fopen(fid);
        fclose(fid);
    end

    format = imftype(filename);
    if (isempty(format))
        error('Unable to determine the file format');
    end
    
else
    % The format was specified explicitly
    
    fid = fopen(filename, 'r');
    if (fid == -1)
        % Couldn't open using the given filename; search for a
        % file with an appropriate extension.
        switch format
        case 'tif'
            fid = fopen([filename '.tif'], 'r');
            if (fid == -1)
                fid = fopen([filename '.tiff'], 'r');
            end
            
        case 'bmp'
            fid = fopen([filename '.bmp'], 'r');
            
        case 'hdf'
            fid = fopen([filename '.hdf'], 'r');
            
        case 'pcx' 
            fid = fopen([filename '.pcx'], 'r');
            
        case 'xwd'
            fid = fopen([filename '.xwd'], 'r');
            
        case 'jpg'
            fid = fopen([filename '.jpg'], 'r');
            if (fid == -1)
                fid = fopen([filename '.jpeg'], 'r');
            end
            
        case 'png'
            fid = fopen([filename '.png'], 'r');

        case 'gif'
            fid = fopen([filename '.gif'], 'r');
        
        case 'cur'
            fid = fopen([filename '.cur'], 'r');
        
        case 'ico'
            fid = fopen([filename '.ico'], 'r');
            
        end
    end
    
    if (fid == -1)
        error(sprintf('Can''t open file "%s" for reading', filename));
        
    else
        filename = fopen(fid);
        fclose(fid);
    end
        
end

alpha = [];

switch format
case 'bmp'
    [X,map] = readbmp(filename, extraArgs{:});
    
case 'xwd'
    [X,map] = readxwd(filename, extraArgs{:});
    
case 'pcx'
    [X,map] = readpcx(filename, extraArgs{:});
    
case 'hdf'
    [X,map] = readhdf(filename, extraArgs{:});
    
case 'tif'
    [X,map] = readtif(filename, extraArgs{:});
    
case 'jpg'
    [X,map] = readjpg(filename, extraArgs{:});
    
case 'png'
    % PNG has slightly different behavior if alpha is
    % requested, so we need the following if statement.
    if (nargout >= 3)
        [X,map,alpha] = readpng(filename, extraArgs{:});
    else
        [X,map] = readpng(filename, extraArgs{:});
    end
case 'gif'
    [X,map] = readgif(filename,extraArgs{:});

case 'cur'
    [X,map,alpha] = readcur(filename, extraArgs{:});
    
case 'ico'
    [X,map,alpha] = readico(filename, extraArgs{:});
    
otherwise
    error(sprintf('Unrecognized or unsupported format "%s"', format));
    
end


%%%
%%% Function parse_inputs
%%%
function [filename, format, extraArgs, msg] = ...
        parse_inputs(varargin)

filename = '';
format = '';
extraArgs = {};
msg = '';

formatStrings = ['bmp'
                 'xwd'
                 'pcx'
                 'hdf'
                 'tif'
                 'jpg'
                 'png'
                 'gif'
                 'cur'
                 'ico'];
             
switch (nargin)
case 0
    msg = 'Too few input arguments';
    return;
    
case 1
    filename = varargin{1};
    
otherwise
    filename = varargin{1};
    
    % Is the second argument a format specifier?
    % Allow some variability in specifying some of the formats.
    arg2 = lower(varargin{2});
    if (strcmp(arg2, 'tiff'))
        arg2 = 'tif';
    elseif (strcmp(arg2, 'jpeg'))
        arg2 = 'jpg';
    end
    idx = strmatch(arg2, formatStrings, 'exact');
    if (~isempty(idx))
        % The second input argument is a format specifier
        format = deblank(formatStrings(idx,:));
        extraArgs = varargin(3:end);
        
    else
        % The second input argument is not a format specifier
        extraArgs = varargin(2:end);
    end
    
end

