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





Попробуйте загрузить поток в System.IO.BinaryReader.
Затем вам нужно будет обратиться к спецификациям для каждого необходимого вам формата изображения и побайтно загрузить заголовок для сравнения со спецификациями. Например вот Технические характеристики PNG
Добавлено: собственно файловая структура для PNG.
Все форматы изображений устанавливают свои начальные байты на определенное значение:
Выполните поиск по запросу «формат файла jpg», заменив jpg на другие форматы файлов, которые вам необходимо определить.
Как рекомендует Гарт, есть база данных таких "магических чисел", показывающий тип файла для многих файлов. Если вам нужно обнаружить много разных типов файлов, стоит просмотреть их, чтобы найти нужную информацию. Если вам действительно нужно расширить это, чтобы охватить многие, многие типы файлов, посмотрите связанный команда файла, который реализует механизм для правильного использования базы данных (это нетривиально для многих форматов файлов и почти статистический процесс)
-Адам
Адам указывает в правильном направлении.
Если вы хотите узнать, как использовать смысл почти любого файла, просмотрите базу данных за командой file на компьютере UNIX, Linux или Mac OS X.
file использует базу данных «магических чисел» - начальных байтов, перечисленных Адамом - для определения типа файла. man file сообщит вам, где найти базу данных на вашем компьютере, например /usr/share/file/magic. man magic сообщит вам свой формат.
Вы можете написать свой собственный код обнаружения на основе того, что вы видите в базе данных, использовать предварительно упакованные библиотеки (например, питон-магия) или - если вы любите приключения В самом деле - реализовать .NET-версию libmagic. Я не смог найти ни одного и надеюсь, что другой участник сможет указать на него.
Если у вас нет под рукой UNIX-машины, база данных выглядит так:
# PNG [Portable Network Graphics, or "PNG's 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
Удачи!
Вероятно, более простым подходом было бы использовать 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
если вы находитесь в контексте веб-приложения, важно использовать полное имя или импортировать сборку, чтобы избежать путаницы с элементом управления Image ... System.Drawing.Image
Существует программный способ определения MIMETYPE изображения.
Есть класс System.Drawing.Imaging.ImageCodecInfo.
Этот класс имеет свойства MimeType и FormatID. Также у него есть метод GetImageEncoders, который возвращает коллекцию всех кодировщиков изображений. Создать Словарь MIME-типов, индексированных по идентификатору формата, несложно.
Класс System.Drawing.Image имеет свойство RawFormat типа System.Drawing.Imaging.ImageFormat, у которого есть свойство Гид, которое эквивалентно свойству 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];
Вы можете использовать приведенный ниже код без ссылки на System.Drawing и ненужного создания объекта Image. Также вы можете использовать решение Алекс даже без потока и ссылки на 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;
}
есть ли аналогичная предсказуемая последовательность для pdf, чтобы мы могли добавить ее в этот список? Спасибо
@ user95227, ага! См. Эту библиотеку: Мим-детектив. Подпись PDF - здесь.
К вашему сведению, это также работает для потоков, использующих System.Drawing.Image.FromStream ()