Подтвердить что ты не робот

Определить, является ли файл изображением

Я перебираю каталог и копирую все файлы. Прямо сейчас я делаю string.EndsWith проверяет ".jpg" или ".png" и т.д. ,

Есть ли более элегантный способ определить, является ли файл изображением (любого типа изображения) без хакерской проверки, как описано выше?

4b9b3361

Ответ 1

Проверьте файл на наличие известного заголовка. (Информация по ссылке также упоминается в этом ответе)

Первые восемь байтов файла PNG всегда содержат следующие (десятичные) значения: 137 80 78 71 13 10 26 10

Ответ 2

Отъезд System.IO.Path.GetExtension

Вот быстрый пример.

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
        }
    }
}

Ответ 3

Это рассмотрит первые несколько байтов файла и определит, является ли это изображением.

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;
    }
}

Изменить

Я сделал несколько изменений выше, чтобы вы могли добавить свои собственные изображения, если вам нужно, а также удалить коллекции, которые не были нужны для начала. Я также добавил перегруз, принимающий параметр out типа string, установив значение в тип изображения, из которого состоит поток.

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;
    }
}

Ответ 4

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

MimeMapping.GetMimeMapping дает следующие результаты:

  • 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 не возвращает образ/тип MIME в большинстве случаев, потому что вы, вероятно, не собираетесь обрабатывать векторное изображение, как скалярное изображение. При проверке типа MIME имейте в виду, что SVG имеет стандартный MIME-тип изображения /svg + xml, даже если GetMimeMapping не возвращает его.

Ответ 5

Мы можем использовать классы изображений и графики из пространства имен System.Drawing; выполнять свою работу. Если код работает без ошибок, это изображение, иначе это не так. Это позволит платформе DotNet выполнять эту работу для нас. Код -

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;
}

Ответ 6

Если вам нужен быстрый способ проверки файла изображения до того, как он будет полностью прочитан из файла, помимо сравнения расширения файла, вы можете просто проверить его заголовок на наличие подписи файла (следующий код IsValidImageFile() проверяет BMP, GIF87a, GIF89a, PNG, TIFF, JPEG)

    /// <summary>
    /// Reads the header of different image formats
    /// </summary>
    /// <param name="file">Image file</param>
    /// <returns>true if valid file signature (magic number/header marker) is found</returns>
    private bool IsValidImageFile(string file)
    {
        byte[] buffer = new byte[8];
        byte[] bufferEnd = new byte[2];

        var bmp = new byte[] { 0x42, 0x4D };               // BMP "BM"
        var gif87a = new byte[] { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 };     // "GIF87a"
        var gif89a = new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 };     // "GIF89a"
        var png = new byte[] { 0x89, 0x50, 0x4e, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };   // PNG "\x89PNG\x0D\0xA\0x1A\0x0A"
        var tiffI = new byte[] { 0x49, 0x49, 0x2A, 0x00 }; // TIFF II "II\x2A\x00"
        var tiffM = new byte[] { 0x4D, 0x4D, 0x00, 0x2A }; // TIFF MM "MM\x00\x2A"
        var jpeg = new byte[] { 0xFF, 0xD8, 0xFF };        // JPEG JFIF (SOI "\xFF\xD8" and half next marker xFF)
        var jpegEnd = new byte[] { 0xFF, 0xD9 };           // JPEG EOI "\xFF\xD9"

        try
        {
            using (System.IO.FileStream fs = new System.IO.FileStream(file, System.IO.FileMode.Open, System.IO.FileAccess.Read))
            {
                if (fs.Length > buffer.Length)
                {
                    fs.Read(buffer, 0, buffer.Length);
                    fs.Position = (int)fs.Length - bufferEnd.Length;
                    fs.Read(bufferEnd, 0, bufferEnd.Length);
                }

                fs.Close();
            }

            if (this.ByteArrayStartsWith(buffer, bmp) ||
                this.ByteArrayStartsWith(buffer, gif87a) ||
                this.ByteArrayStartsWith(buffer, gif89a) ||
                this.ByteArrayStartsWith(buffer, png) ||
                this.ByteArrayStartsWith(buffer, tiffI) ||
                this.ByteArrayStartsWith(buffer, tiffM))
            {
                return true;
            }

            if (this.ByteArrayStartsWith(buffer, jpeg))
            {
                // Offset 0 (Two Bytes): JPEG SOI marker (FFD8 hex)
                // Offest 1 (Two Bytes): Application segment (FF?? normally ??=E0)
                // Trailer (Last Two Bytes): EOI marker FFD9 hex
                if (this.ByteArrayStartsWith(bufferEnd, jpegEnd))
                {
                    return true;
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, Lang.Lang.ErrorTitle + " IsValidImageFile()", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        return false;
    }

    /// <summary>
    /// Returns a value indicating whether a specified subarray occurs within array
    /// </summary>
    /// <param name="a">Main array</param>
    /// <param name="b">Subarray to seek within main array</param>
    /// <returns>true if a array starts with b subarray or if b is empty; otherwise false</returns>
    private bool ByteArrayStartsWith(byte[] a, byte[] b)
    {
        if (a.Length < b.Length)
        {
            return false;
        }

        for (int i = 0; i < b.Length; i++)
        {
            if (a[i] != b[i])
            {
                return false;
            }
        }

        return true;
    }

Проверка подписи заголовка может быть быстрой, так как она не загружает весь файл или создает большие объекты, особенно при обработке нескольких файлов. Но он не проверяет, правильно ли сформированы остальные данные. Для этого можно выполнить второй шаг, чтобы попытаться загрузить файл в объект Image (и таким образом быть уверенным, что файл может отображаться и обрабатываться вашей программой).

bool IsValidImage(string filename)
{
    try
    {
        using(Image newImage = Image.FromFile(filename))
        {}
    }
    catch (OutOfMemoryException ex)
    {
        //The file does not have a valid image format.
        //-or- GDI+ does not support the pixel format of the file

        return false;
    }
    return true;
}

Ответ 7

Я использую следующий метод. Он использует встроенный декодер изображений для получения списка расширений, которые система распознает как файлы изображений, а затем сравнивает эти расширения с расширением имени файла, в котором вы проходите. Возвращает простой TRUE/FALSE.

public static bool IsRecognisedImageFile(string fileName)
{
    string targetExtension = System.IO.Path.GetExtension(fileName);
    if (String.IsNullOrEmpty(targetExtension))
        return false;
    else
        targetExtension = "*" + targetExtension.ToLowerInvariant();

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

    foreach (System.Drawing.Imaging.ImageCodecInfo imageCodec in System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders())
        recognisedImageExtensions.AddRange(imageCodec.FilenameExtension.ToLowerInvariant().Split(";".ToCharArray()));

    foreach (string extension in recognisedImageExtensions)
    {
        if (extension.Equals(targetExtension))
        {
            return true;
        }
    }
    return false;
}

Ответ 8

Посмотрите, помогает ли это.

EDIT: также Image.FromFile(....). RawFormat может помочь. Он может генерировать исключение, если файл не является изображением.

Ответ 9

Не тот ответ, который вам нужен. Но если это Интернет, то MIME.

Ответ 10

Я не уверен, каков был бы недостаток производительности для этого решения, но вы не могли бы выполнить какую-либо функцию изображения в файле в блоке try, который не смог бы и упал бы до блока catch, если это не изображение?

Эта стратегия может быть не лучшим решением во всех ситуациях, но в том случае, если я в настоящее время работаю с ней, есть одно важное преимущество: Вы можете использовать любую функцию, которую вы планируете использовать для обработки изображения (если это изображение) для тестовой функции. Таким образом, вы можете протестировать все текущие типы изображений, но он также будет распространяться на будущие типы изображений, не добавляя это новое расширение изображения в список поддерживаемых типов изображений.

Кто-нибудь видит недостатки в этой стратегии?

Ответ 11

Это то, что я использую - это всего лишь небольшая настройка ответа @dylmcc, чтобы сделать его более читабельным.

public static bool IsRecognisedImageFile(string fileName)
{
    string targetExtension = System.IO.Path.GetExtension(fileName);
    if (String.IsNullOrEmpty(targetExtension))
    {
        return false;
    }

    var recognisedImageExtensions = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders().SelectMany(codec => codec.FilenameExtension.ToLowerInvariant().Split(';'));

    targetExtension = "*" + targetExtension.ToLowerInvariant();
    return recognisedImageExtensions.Contains(targetExtension);
}

Ответ 12

Мой простой код

public static List<string> GetAllPhotosExtensions()
    {
        var list = new List<string>();
        list.Add(".jpg");
        list.Add(".png");
        list.Add(".bmp");
        list.Add(".gif");
        list.Add(".jpeg");
        list.Add(".tiff");
        return list;
    }

Проверьте, если файл изображения

public static bool IsPhoto(string fileName)
    {
        var list = FileListExtensions.GetAllPhotosExtensions();
        var filename= fileName.ToLower();
        bool isThere = false;
        foreach(var item in list)
        {
            if (filename.EndsWith(item))
            {
                isThere = true;
                break;
            }
        }
        return isThere;     
    }

Ответ 13

Это хитрый. Если файл не является изображением, будет выдано исключение. Из этого мы можем проверить, является ли файл изображением или нет.

        using (Stream stream = File.OpenRead(file))
           {
               try
               {
                   using (Image sourceImage = Image.FromStream(stream, false, false))
                   {

                   }
               }
               catch (Exception x)
               {
                   if (x.Message.Contains("not valid"))
                   {
                     Console.Write("This is not a Image.");
                   }

               }
           }