2008-09-11 53 views
42

我正在从一个服务中下载一些图像,该图像并不总是包含内容类型,也没有为我正在下载的文件提供扩展名(呃,不要问) 。确定图像的文件类型

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

正在阅读这些下载图像的应用程序需要具有适当的文件扩展名或者所有地狱都会打散。

回答

51

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

仅供参考,这也适用于使用System.Drawing.Image.FromStream() – jishi 2010-06-23 10:31:44

+0

流。如果您在Web应用程序的环境中,会使用完全合格的名称或进口组装,以避免很重要与图像控制混淆... System.Drawing.Image – MacGyver 2012-01-22 00:55:58

0

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

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

增加:PNG的实际file structure

21

所有图像格式设置它们的初始字节为特定值:

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

正如Garth的建议,有一个database of such 'magic numbers'显示许多文件的文件类型。如果您必须检测许多不同的文件类型,则需要查看它以查找所需的信息。如果你确实需要扩展它来覆盖很多很多的文件类型,看看相关的file command,它实现了引擎来正确地使用数据库(对许多文件格式来说这是不重要的,并且几乎是一个统计过程)

- 亚当

8

亚当正指着正确的方向。

如果您想了解如何感测几乎任何文件,请查看UNIX,Linux或Mac OS X机器上的file命令背后的数据库。

file使用“幻数”数据库 - 亚当列出的最初字节 - 来检测文件的类型。 man file会告诉你在哪里可以找到你的机器上的数据库,例如/usr/share/file/magicman magic会告诉你它的format

您可以编写一个基于你在数据库中看到自己的检测代码,使用预包装库(例如python-magic),或者 - 如果你真的冒险 - 实施libmagic一个.NET版本。我找不到一个,并希望另一个成员可以指出一个。

如果你没有一台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 

祝你好运!

2

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

还有类System.Drawing.Imaging.ImageCodecInfo

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

为System.Drawing.Image具有属性类型System.Drawing.Imaging.ImageFormat的RawFormat具有属性的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]; 
18

可以使用下面的代码,而不System.Drawing中的参考和对象的不必要创建图片。即使没有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; 
}