.net 确定图像的文件类型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/55869/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 09:47:26  来源:igfitidea点击:

Determine file type of an image

.netimagecontent-typemime-types

提问by Eric

I'm downloading some images from a service that doesn't always include a content-type and doesn't provide an extension for the file I'm downloading (ugh, don't ask).

我正在从一项服务下载一些图像,该服务并不总是包含内容类型,也不为我正在下载的文件提供扩展名(呃,别问了)。

What's the best way to determine the image format in .NET?

在 .NET 中确定图像格式的最佳方法是什么?

The application that is reading these downloaded images needs to have a proper file extension or all hell breaks loose.

正在读取这些下载图像的应用程序需要具有适当的文件扩展名,否则一切都会崩溃。

回答by Vinko Vrsalovic

A probably easier approach would be to use Image.FromFile() and then use the RawFormat property, as it already knows about the magic bits in the headers for the most common formats, like this:

一个可能更简单的方法是使用 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

回答by Ivan Kochurkin

You can use code below without reference of System.Drawing and unnecessary creation of object Image. Also you can use Alexsolution even without stream and reference of System.IO.

您可以在不引用 System.Drawing 和不必要创建对象 Image 的情况下使用下面的代码。即使没有 System.IO 的流和引用,您也可以使用Alex解决方案。

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

回答by Adam Davis

All the image formats set their initial bytes to a particular value:

所有图像格式都将其初始字节设置为特定值:

Search for "jpg file format" replacing jpg with the other file formats you need to identify.

搜索“jpg 文件格式”,用您需要识别的其他文件格式替换 jpg。

As Garth recommends, there is a database of such 'magic numbers'showing the file type of many files. If you have to detect a lot of different file types it's worthwhile looking through it to find the information you need. If you do need to extend this to cover many, many file types, look at the associated file commandwhich implements the engine to use the database correctly (it's non trivial for many file formats, and is almost a statistical process)

正如 Garth 所建议的,有一个这样的“神奇数字”数据库,显示了许多文件的文件类型。如果您必须检测许多不同的文件类型,则值得仔细查看以找到您需要的信息。如果您确实需要扩展它以涵盖很多很多文件类型,请查看相关的文件命令,该命令实现了引擎以正确使用数据库(对于许多文件格式来说这很重要,并且几乎是一个统计过程)

-Adam

-亚当

回答by Garth Kidd

Adam is pointing in exactly the right direction.

亚当指向的方向完全正确。

If you want to find out how to sense almost any file, look at the database behind the filecommand on a UNIX, Linux, or Mac OS X machine.

如果您想了解如何检测几乎所有文件,请查看fileUNIX、Linux 或 Mac OS X 机器上命令背后的数据库。

fileuses a database of “magic numbers” — those initial bytes Adam listed — to sense a file's type. man filewill tell you where to find the database on your machine, e.g. /usr/share/file/magic. man magicwill tell you its format.

file使用“幻数”数据库——亚当列出的那些初始字节——来感知文件的类型。man file会告诉你在哪里可以找到你机器上的数据库,例如/usr/share/file/magicman magic会告诉你它的格式

You can either write your own detection code based on what you see in the database, use pre-packaged libraries (e.g. python-magic), or — if you're reallyadventurous — implement a .NET version of libmagic. I couldn't find one, and hope another member can point one out.

您可以根据您在数据库中看到的内容编写自己的检测代码,使用预先打包的库(例如python-magic),或者 - 如果您真的喜欢冒险 - 实现 .NET 版本的libmagic. 我找不到,希望另一位成员可以指出。

In case you don't have a UNIX machine handy, the database looks like this:

如果您手头没有 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

Good luck!

祝你好运!

回答by slobodans

There is programmatic way to determine image MIMETYPE.

有确定图像 MIMETYPE 的编程方式。

There is class System.Drawing.Imaging.ImageCodecInfo.

有类System.Drawing.Imaging.ImageCodecInfo

This class have properties MimeTypeand FormatID. Also it have a method GetImageEncoderswhich return collection of all image encoders. It is easy to create Dictionary of mime types indexed by format id.

此类具有MimeTypeFormatID属性。它还有一个方法GetImageEncoders返回所有图像编码器的集合。很容易创建按格式 ID 索引的 mime 类型字典。

Class System.Drawing.Imagehave property RawFormatof Type System.Drawing.Imaging.ImageFormatwhich have property Guidwhich is equivalent of the property FormatIDof class System.Drawing.Imaging.ImageCodecInfo, and that is key to take MIMETYPE from dictionary.

为System.Drawing.Image有属性RawFormat类型的System.Drawing.Imaging.ImageFormat具有属性的Guid这相当于属性的FormatID类的System.Drawing.Imaging.ImageCodecInfo,这是关键采取MIMETYPE从字典。

Example:

例子:

Static method to create dictionary of mime types

创建 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;
}

Use:

用:

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

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

回答by Ash

Try loading the stream into a System.IO.BinaryReader.

尝试将流加载到 System.IO.BinaryReader 中。

Then you will need to refer to the specifications for each image format you need, and load the header byte by byte to compare against the specifications. For example here are the PNG specifications

然后您需要参考您需要的每种图像格式的规范,并逐字节加载标题以与规范进行比较。例如这里是PNG规范

Added: The actual file structurefor PNG.

补充:PNG的实际文件结构