2009-03-22 4 views
32

Я перебираю каталог и копирую все файлы. Прямо сейчас я делаю string.EndsWith проверки на «.jpg» или «.png» и т. Д. ,определить, является ли файл изображением

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

+2

Есть ли причина расширения недостаточно? – peterchen

+0

См. Также: http://stackoverflow.com/questions/9354747/how-can-i-determine-if-a-file-is-an-image-file-in-net – Daryl

ответ

28

Проверьте файл на known header. (Информация из ссылки также упоминается в this answer)

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

+0

Вау, Кларион все еще вокруг! Это сюрприз - я вырезал один или два зуба на Clarion еще примерно в 95 году. – ProfK

+0

Обратите внимание, что символы от второго до шестого являются «PNG \ r \ n» –

+25

Извините, но ваша ссылка больше не работала. У меня ошибка 403. –

22

Заканчивать 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 
     } 
    } 
} 
+1

erm, это то, что плакат говорит, что он хочет сделать больше, чем .... –

+1

Он сказал, что проверяет, есть ли строка. С тех пор, как я собрал – bendewey

+7

, да, но это все еще сравнение строк. Что делать, если я переименую файл .jpf как .txt? –

5

Посмотрите, подходит ли this.

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

2

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

2

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

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

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

+1

Целевое использование try/catch нежелательно, так как исключения/могут быть дорогими (над головой мудрыми), и у него есть легкий запах кода. Это не изящное решение. Пожалуйста, см. Dylmcc для лучшего решения. Я использовал его, и он работает. Я не вижу никаких обратных ссылок на это решение. –

4

Я использую следующий метод. Он использует встроенный декодер изображений для получения списка расширений, которые система распознает как файлы изображений, а затем сравнивает эти расширения с расширением имени файла, в котором вы проходите. Возвращает простой 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; 
} 
+0

Это хорошо работает как частичная замена для http://stackoverflow.com/a/14587821/329367 – Darren

13

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

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

непрактично, поскольку вам не хватает множества возможных типов изображений. –

+2

Несколько опечаток: Должно быть return IsImage (stream, out imageType); вместо return stream.IsImage (out imageType); Должно быть INT largestByteHeader = ImageTypes.Max (IMG => img.Key.Length) вместо INT largestByteHeader = ImageTypes.Max (IMG => img.Value.Length) –

+2

Реализовать то, что вы только что написали и посмотреть если он даже компилирует –

11

Мы можем использовать классы изображений и графики из пространства имен 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; 
} 
+1

Добавьте этот код в раздел: 'imgInput.Dispose(); gInput.Dispose(); '. Если дескриптор файла не будет открыт, а другие процессы не смогут его использовать. – Beginner

+1

Позаботьтесь: во время работы он будет использовать системные ресурсы и память.Хорошо для нескольких проверок изображения здесь и там, но не для веб-среды, где люди могут загружать изображения любого размера. –

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

MimeMapping.GetMimeMapping производит эти результаты:

  • File.jpg: изображение/JPEG
  • file.gif: изображение/GIF
  • file.jpeg: изображение/jpeg
  • file.png: image/png
  • file.bmp: изображение/BMP
  • file.tiff: изображение/размолвка
  • file.svg: приложения/октет-поток

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

+2

, если расширение файла намеренно изменено, например. от .jpg до .txt, это не сработает. Выходной файл System.Web.MimeMapping.GetMimeMapping (filename) будет текстовым/обычным – amyn