2008-09-11 49 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; 
}