2008-09-11 20 views
42

Ich lade einige Bilder von einem Dienst herunter, der nicht immer einen Inhaltstyp enthält, und bietet keine Erweiterung für die Datei, die ich herunterlade (hm, frag nicht) .Ermitteln des Dateityps eines Bildes

Was ist der beste Weg, um das Bildformat in .NET zu bestimmen?

Die Anwendung, die diese heruntergeladenen Bilder liest, muss eine richtige Dateierweiterung haben oder die Hölle bricht los.

Antwort

51

Ein wahrscheinlich einfacher Ansatz wäre Image.FromFile() zu verwenden und dann die RawFormat Eigenschaft verwenden, da sie bereits über die magische Bits in den Header für die gängigsten Formate weiß, wie folgt aus:

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

FYI, dies auch für Ströme arbeitet mit System.Drawing.Image.FromStream() – jishi

+0

, wenn Sie im Rahmen einer Web-Anwendung sind, ist es wichtig, den vollständig qualifizierten Namen zu verwenden oder die Baugruppe importieren zu vermeiden Verwirrung mit einem Image-Steuerelement ... System.Drawing.Image – MacGyver

0

Versuchen Sie, den Stream in einen System.IO.BinaryReader zu laden.

Dann müssen Sie auf die Spezifikationen für jedes Bildformat verweisen, das Sie benötigen, und laden Sie die Kopfzeile Byte für Byte, um sie mit den Spezifikationen zu vergleichen. Zum Beispiel hier sind die PNG specifications

Hinzugefügt: Die tatsächliche file structure für PNG.

21

Alle Bildformate setzen ihre anfänglichen Bytes auf einen bestimmten Wert:

Suche nach „jpg-Dateiformat "Ersetzen Sie JPG durch die anderen Dateiformate, die Sie identifizieren müssen.

Wie Garth empfiehlt, gibt es einen database of such 'magic numbers', der den Dateityp vieler Dateien anzeigt. Wenn Sie viele verschiedene Dateitypen erkennen müssen, lohnt es sich, durchzublättern, um die benötigten Informationen zu finden. Wenn Sie dies erweitern müssen, um viele, viele Dateitypen abzudecken, sehen Sie sich die zugehörige file command an, die die Engine implementiert, um die Datenbank korrekt zu verwenden (dies ist für viele Dateiformate nicht trivial und ist fast ein statistischer Prozess)

- Adam

8

Adam zeigt in genau die richtige Richtung.

Wenn Sie möchten, um herauszufinden, wie auf Sinn fast jede Datei, Blick auf die Datenbank hinter dem file Befehl auf einem UNIX, Linux oder Mac OS X-Maschine.

file verwendet eine Datenbank mit "magischen Zahlen" - diese Anfangs-Bytes, die Adam aufgelistet hat - um den Typ einer Datei zu erkennen. man file wird Ihnen sagen, wo Sie die Datenbank auf Ihrem Computer finden, z. /usr/share/file/magic. man magic wird Ihnen seine format mitteilen.

Sie können entweder Ihren eigenen Erkennungscode schreiben auf, was Sie in der Datenbank zu sehen, verwendet abgepackte Bibliotheken (z python-magic), oder - wenn Sie wirklich abenteuerlich - implementieren eine .NET-Version von libmagic. Ich konnte keinen finden und hoffe, ein anderes Mitglied kann darauf hinweisen.

Falls Sie nicht ein UNIX-Rechner zur Hand haben, sieht die Datenbank wie folgt aus:

 
# 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 

Viel Glück!

2

Es gibt einen programmatischen Weg, um Image MIMETYPE zu bestimmen.

Es gibt Klasse System.Drawing.Imaging.ImageCodecInfo.

Diese Klasse haben Eigenschaften Mimetype und formatID. Es hat auch eine Methode GetImageEncoders, die Sammlung aller Bildgeber zurückgeben. Es ist einfach zu erstellen Wörterbuch der Mime-Typen durch Format-ID indiziert.

Klasse System.Drawing.Image haben Eigenschaft RawFormat von Typ System.Drawing.Imaging.ImageFormat die Eigenschaft haben Guid die der Immobilie entspricht formatID der Klasse System.Drawing. Imaging.ImageCodecInfo, und das ist der Schlüssel, um MIMETYPE aus dem Wörterbuch zu nehmen.

Beispiel:

Statische Methode Wörterbuch von Mime-Typen erstellen

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

Verwendung:

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

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

Sie folgenden Code ohne Bezug von System.Drawing und unnötige Erzeugung von Objekt verwenden können, Bild. Auch können Sie Alex Lösung auch ohne Stream und Referenz von System.IO verwenden.

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

gibt es eine ähnliche vorhersagbare Reihenfolge für PDF, so dass wir es zu dieser Liste hinzufügen könnten? Danke – user95227

+1

@ user95227, yep! Siehe diese Lib: [Mime-Detective] (https://github.com/Muraad/Mime-Detective). PDF-Signatur ist [hier] (https://github.com/Muraad/Mime-Detective/blob/master/MimeDetective/MimeTypes.cs#L47). –