определить, является ли файл изображением - PullRequest
40 голосов
/ 22 марта 2009

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

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

Ответы [ 11 ]

31 голосов
/ 22 марта 2009

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

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

25 голосов
/ 22 марта 2009

Проверить 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
        }
    }
}
15 голосов
/ 09 июня 2016
System.Web.MimeMapping.GetMimeMapping(filename).StartsWith("image/");

MimeMapping.GetMimeMapping дает такие результаты:

  • file.jpg: изображение / JPEG
  • file.gif: изображение / 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 не возвращает его.

15 голосов
/ 26 августа 2014

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

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;
    }
}
12 голосов
/ 05 июля 2015

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

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;
}
7 голосов
/ 06 апреля 2018

Если вам нужен быстрый способ проверки файла изображения до того, как он будет полностью прочитан из файла, помимо сравнения расширения файла, вы можете просто проверить его заголовок на наличие подписи файла (следующий код 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;
}
5 голосов
/ 05 июня 2014

Я использую следующий метод. Он использует встроенный декодер изображений для получения списка расширений, которые система распознает как файлы изображений, а затем сравнивает эти расширения с расширением переданного вами имени файла. Возвращает простое значение ИСТИНА / ЛОЖЬ.

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;
}
5 голосов
/ 22 марта 2009

Посмотрите, поможет ли .

РЕДАКТИРОВАТЬ: Кроме того, Image.FromFile (....). RawFormat может помочь. Может выдать исключение, если файл не является изображением.

2 голосов
/ 01 октября 2012

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

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

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

2 голосов
/ 22 марта 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...