determine if file is an image

107,131

Solution 1

Check the file for a known header. (Info from link also mentioned in this answer)

The first eight bytes of a PNG file always contain the following (decimal) values: 137 80 78 71 13 10 26 10

Solution 2

Check out System.IO.Path.GetExtension

Here is a quick sample.

public static readonly List<string> ImageExtensions = new List<string> { ".JPG", ".JPE", ".BMP", ".GIF", ".PNG" };

private void button_Click(object sender, RoutedEventArgs e)
{
    var folder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
    var files = Directory.GetFiles(folder);
    foreach(var f in files)
    {
        if (ImageExtensions.Contains(Path.GetExtension(f).ToUpperInvariant()))
        {
            // process image
        }
    }
}

Solution 3

System.Web.MimeMapping.GetMimeMapping(filename).StartsWith("image/");

MimeMapping.GetMimeMapping produces these results:

  • file.jpg: image/jpeg
  • file.gif: image/gif
  • file.jpeg: image/jpeg
  • file.png: image/png
  • file.bmp: image/bmp
  • file.tiff: image/tiff
  • file.svg: application/octet-stream

file.svg not returning an image/ MIME type works out in most cases because you're probably not going to process a vector image like you would a scalar image. When checking MIME type, do be aware that SVG does have the standard MIME type of image/svg+xml, even if GetMimeMapping doesn't return it.

Solution 4

This will look at the first few bytes of a file and determine whether it is an image.

using System.Collections.Generic;
using System.IO;
using System.Linq;

public static class Extension
{
    public static bool IsImage(this Stream stream)
    {
        stream.Seek(0, SeekOrigin.Begin);

        List<string> jpg = new List<string> { "FF", "D8" };
        List<string> bmp = new List<string> { "42", "4D" };
        List<string> gif = new List<string> { "47", "49", "46" };
        List<string> png = new List<string> { "89", "50", "4E", "47", "0D", "0A", "1A", "0A" };
        List<List<string>> imgTypes = new List<List<string>> { jpg, bmp, gif, png };

        List<string> bytesIterated = new List<string>();

        for (int i = 0; i < 8; i++)
        {
            string bit = stream.ReadByte().ToString("X2");
            bytesIterated.Add(bit);

            bool isImage = imgTypes.Any(img => !img.Except(bytesIterated).Any());
            if (isImage)
            {
                return true;
            }
        }

        return false;
    }
}

Edit

I've made a few changes to the above to allow you to add your own images if you needed to, also removed collections which weren't necessary to begin with. I also added an overload accepting an out parameter of type string, setting the value to the type of image the stream is composed of.

public static class Extension
{
    static Extension()
    {
        ImageTypes = new Dictionary<string, string>();
        ImageTypes.Add("FFD8","jpg");
        ImageTypes.Add("424D","bmp");
        ImageTypes.Add("474946","gif");
        ImageTypes.Add("89504E470D0A1A0A","png");
    }
    
    /// <summary>
    ///     <para> Registers a hexadecimal value used for a given image type </para>
    ///     <param name="imageType"> The type of image, example: "png" </param>
    ///     <param name="uniqueHeaderAsHex"> The type of image, example: "89504E470D0A1A0A" </param>
    /// </summary>
    public static void RegisterImageHeaderSignature(string imageType, string uniqueHeaderAsHex)
    {
        Regex validator = new Regex(@"^[A-F0-9]+$", RegexOptions.CultureInvariant);
    
        uniqueHeaderAsHex = uniqueHeaderAsHex.Replace(" ", "");
        
        if (string.IsNullOrWhiteSpace(imageType))         throw new ArgumentNullException("imageType");
        if (string.IsNullOrWhiteSpace(uniqueHeaderAsHex)) throw new ArgumentNullException("uniqueHeaderAsHex");
        if (uniqueHeaderAsHex.Length % 2 != 0)            throw new ArgumentException    ("Hexadecimal value is invalid");
        if (!validator.IsMatch(uniqueHeaderAsHex))        throw new ArgumentException    ("Hexadecimal value is invalid");
        
        ImageTypes.Add(uniqueHeaderAsHex, imageType);
    }
    
    private static Dictionary<string, string> ImageTypes;

    public static bool IsImage(this Stream stream)
    {
        string imageType;
        return stream.IsImage(out imageType);
    }
    
    public static bool IsImage(this Stream stream, out string imageType)
    {
        stream.Seek(0, SeekOrigin.Begin);
        StringBuilder builder = new StringBuilder();
        int largestByteHeader = ImageTypes.Max(img => img.Value.Length);
        
        for (int i = 0; i < largestByteHeader; i++)
        {
            string bit = stream.ReadByte().ToString("X2");
            builder.Append(bit);
            
            string builtHex = builder.ToString();
            bool isImage = ImageTypes.Keys.Any(img => img == builtHex);
            if (isImage)
            {
                imageType = ImageTypes[builder.ToString()];
                return true;
            }
        }
        imageType = null;
        return false;
    }
}

Solution 5

We can use Image and graphics classes from namespace System.Drawing; to do our job. If the code works without error it is an image, else it is not. That is let the DotNet framework do the job for us. The code -

public string CheckFile(file)
{
    string result="";
    try
    {
        System.Drawing.Image imgInput = System.Drawing.Image.FromFile(file);
        System.Drawing.Graphics gInput = System.Drawing.Graphics.fromimage(imgInput);  
        Imaging.ImageFormat thisFormat = imgInput.RawFormat;   
        result="It is image";        
    }
    catch(Exception ex)
    {
        result="It is not image"; 
    }
    return result;
}
Share:
107,131
leora
Author by

leora

Updated on August 14, 2020

Comments

  • leora
    leora almost 4 years

    I am looping through a directory and copying all files. Right now I am doing string.EndsWith checks for ".jpg" or ".png", etc . .

    Is there any more elegant way of determining if a file is an image (any image type) without the hacky check like above?