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

Я загружаю некоторые изображения из службы, которая не всегда включает тип содержимого и не предоставляет расширение для файла, который я загружаю (ugh, не спрашивайте).

Какой лучший способ определить формат изображения в .NET?

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

Ответ 1

Вероятнее всего, проще использовать Image.FromFile(), а затем использовать свойство RawFormat, поскольку он уже знает о волшебных битах в заголовках для наиболее распространенных форматов, например:

Image i = Image.FromFile("c:\\foo");
if (System.Drawing.Imaging.ImageFormat.Jpeg.Equals(i.RawFormat)) 
    MessageBox.Show("JPEG");
else if (System.Drawing.Imaging.ImageFormat.Gif.Equals(i.RawFormat))
    MessageBox.Show("GIF");
//Same for the rest of the formats

Ответ 2

Все форматы изображений устанавливают начальные байты на определенное значение:

Найдите "формат файла jpg", заменив jpg на другие форматы файлов, которые вам нужно идентифицировать.

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

-Adam

Ответ 3

Вы можете использовать код ниже без ссылки на System.Drawing и ненужное создание объекта Image. Также вы можете использовать Alex даже без потока и ссылки System.IO.

public enum ImageFormat
{
    bmp,
    jpeg,
    gif,
    tiff,
    png,
    unknown
}

public static ImageFormat GetImageFormat(Stream stream)
{
    // see http://www.mikekunz.com/image_file_header.html
    var bmp = Encoding.ASCII.GetBytes("BM");     // BMP
    var gif = Encoding.ASCII.GetBytes("GIF");    // GIF
    var png = new byte[] { 137, 80, 78, 71 };    // PNG
    var tiff = new byte[] { 73, 73, 42 };         // TIFF
    var tiff2 = new byte[] { 77, 77, 42 };         // TIFF
    var jpeg = new byte[] { 255, 216, 255, 224 }; // jpeg
    var jpeg2 = new byte[] { 255, 216, 255, 225 }; // jpeg canon

    var buffer = new byte[4];
    stream.Read(buffer, 0, buffer.Length);

    if (bmp.SequenceEqual(buffer.Take(bmp.Length)))
        return ImageFormat.bmp;

    if (gif.SequenceEqual(buffer.Take(gif.Length)))
        return ImageFormat.gif;

    if (png.SequenceEqual(buffer.Take(png.Length)))
        return ImageFormat.png;

    if (tiff.SequenceEqual(buffer.Take(tiff.Length)))
        return ImageFormat.tiff;

    if (tiff2.SequenceEqual(buffer.Take(tiff2.Length)))
        return ImageFormat.tiff;

    if (jpeg.SequenceEqual(buffer.Take(jpeg.Length)))
        return ImageFormat.jpeg;

    if (jpeg2.SequenceEqual(buffer.Take(jpeg2.Length)))
        return ImageFormat.jpeg;

    return ImageFormat.unknown;
}

Ответ 4

Адам указывает в правильном направлении.

Если вы хотите узнать, как воспринимать почти любой файл, посмотрите на базу данных за командой file на компьютере UNIX, Linux или Mac OS X.

file использует базу данных "магических чисел" - эти начальные байты, перечисленные Адамом, - для определения типа файла. man file сообщит вам, где найти базу данных на вашем компьютере, например. /usr/share/file/magic. man magic сообщит вам свой формат.

Вы можете написать свой собственный код обнаружения на основе того, что видите в базе данных, использовать предварительно упакованные библиотеки (например, python-magic), или - если вы действительно предприимчивы - реализуйте .NET-версию libmagic. Я не мог найти его, и надеюсь, что другой член может указать на него.

Если у вас нет машины UNIX, база данных выглядит следующим образом:

# PNG [Portable Network Graphics, or "PNG Not GIF"] images
# (Greg Roelofs, [email protected])
# (Albert Cahalan, [email protected])
#
# 137 P N G \r \n ^Z \n [4-byte length] H E A D [HEAD data] [HEAD crc] ...
#
0       string          \x89PNG         PNG image data,
>4      belong          !0x0d0a1a0a     CORRUPTED,
>4      belong          0x0d0a1a0a
>>16    belong          x               %ld x
>>20    belong          x               %ld,
>>24    byte            x               %d-bit
>>25    byte            0               grayscale,
>>25    byte            2               \b/color RGB,
>>25    byte            3               colormap,
>>25    byte            4               gray+alpha,
>>25    byte            6               \b/color RGBA,
#>>26   byte            0               deflate/32K,
>>28    byte            0               non-interlaced
>>28    byte            1               interlaced
1       string          PNG             PNG image data, CORRUPTED

# GIF
0       string          GIF8            GIF image data
>4      string          7a              \b, version 8%s,
>4      string          9a              \b, version 8%s,
>6      leshort         >0              %hd x
>8      leshort         >0              %hd
#>10    byte            &0x80           color mapped,
#>10    byte&0x07       =0x00           2 colors
#>10    byte&0x07       =0x01           4 colors
#>10    byte&0x07       =0x02           8 colors
#>10    byte&0x07       =0x03           16 colors
#>10    byte&0x07       =0x04           32 colors
#>10    byte&0x07       =0x05           64 colors
#>10    byte&0x07       =0x06           128 colors
#>10    byte&0x07       =0x07           256 colors

Удачи!

Ответ 5

Существует программный способ определения изображения MIMETYPE.

Существует класс System.Drawing.Imaging.ImageCodecInfo.

Этот класс имеет свойства MimeType и FormatID. Также он имеет метод GetImageEncoders, который возвращает коллекцию всех кодеров изображений. Легко создать словарь типов mime, индексированных по идентификатору формата.

Класс System.Drawing.Image имеет свойство RawFormat типа System.Drawing.Imaging.ImageFormat, у которого есть свойство Guid, который эквивалентен свойству FormatID класса System.Drawing.Imaging.ImageCodecInfo, и это ключ к использованию MIMETYPE из словаря.

Пример:

Статический метод создания словаря типов mime

static Dictionary<Guid, string> GetImageFormatMimeTypeIndex()
{
  Dictionary<Guid, string> ret = new Dictionary<Guid, string>();

  var encoders = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders();

  foreach(var e in encoders)
  {
    ret.Add(e.FormatID, e.MimeType);
  }

  return ret;
}

Использование:

Dictionary<Guid, string> mimeTypeIndex = GetImageFormatMimeTypeIndex();

FileStream imgStream = File.OpenRead(path);
var image = System.Drawing.Image.FromStream(imgStream);
string mimeType = mimeTypeIndex[image.RawFormat.Guid];

Ответ 6

Попробуйте загрузить поток в System.IO.BinaryReader.

Затем вам нужно будет обратиться к спецификациям для каждого формата изображения, который вам нужен, и загрузить байт заголовка байтом для сравнения с спецификациями. Например, спецификации PNG

Добавлено: фактическая структура для PNG.