Определить тип файла изображения - PullRequest
45 голосов
/ 11 сентября 2008

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

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

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

Ответы [ 6 ]

54 голосов
/ 11 сентября 2008

Возможно, более простым подходом было бы использовать 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
22 голосов
/ 17 сентября 2012

Вы можете использовать приведенный ниже код без ссылки на 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;
}
22 голосов
/ 11 сентября 2008

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

Поиск "jpg file format", заменяющий jpg другими форматами файлов, которые вам необходимо определить.

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

-Adam

8 голосов
/ 11 сентября 2008

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

Если вы хотите узнать, как воспринимать практически любой файл , посмотрите на базу данных, стоящую за командой 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's Not GIF"] images
# (Greg Roelofs, newt@uchicago.edu)
# (Albert Cahalan, acahalan@cs.uml.edu)
#
# 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

Удачи!

3 голосов
/ 21 августа 2012

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

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

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

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

* 1 028 * Пример:

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

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];
0 голосов
/ 11 сентября 2008

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

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

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

...