2008-09-11 10 views
42

Je télécharge des images à partir d'un service qui n'inclut pas toujours un type de contenu et ne fournit pas d'extension pour le fichier que je télécharge (pouah, ne demande pas) .Déterminer le type de fichier d'une image

Quelle est la meilleure façon de déterminer le format d'image dans .NET?

L'application qui lit ces images téléchargées doit avoir une extension de fichier appropriée ou tout se déchaîne.

Répondre

51

Une approche sans doute plus facile serait d'utiliser Image.FromFile(), puis utiliser la propriété RawFormat, car il connaît déjà les bits magiques dans les en-têtes pour les formats les plus courants, comme celui-ci:

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

Pour votre information, cela fonctionne aussi pour les flux en utilisant System.Drawing.Image.FromStream() – jishi

+0

si vous êtes dans le cadre d'une application web, il est important d'utiliser le nom complet ou importer l'ensemble pour éviter confusion avec un contrôle Image ... System.Drawing.Image – MacGyver

0

Essayez de charger le flux dans un System.IO.BinaryReader.

Ensuite, vous devrez vous référer aux spécifications pour chaque format d'image dont vous avez besoin, et charger l'octet d'en-tête par octet pour comparer avec les spécifications. Par exemple voici les PNG specifications

Ajouté: Le réel pour PNG.

21

Tous les formats d'image fixent leurs premiers octets à une valeur particulière:

Chercher « jpg format de fichier "remplacer jpg avec les autres formats de fichiers que vous devez identifier.

Comme le recommande Garth, il existe un database of such 'magic numbers' indiquant le type de fichier de nombreux fichiers. Si vous devez détecter un grand nombre de types de fichiers différents, il est utile de le parcourir pour trouver les informations dont vous avez besoin. Si vous devez étendre cela pour couvrir beaucoup, beaucoup de types de fichiers, regardez le file command associé qui implémente le moteur pour utiliser la base de données correctement (c'est non trivial pour de nombreux formats de fichiers, et est presque un processus statistique)

- Adam

8

Adam pointe exactement dans la bonne direction.

Si vous voulez savoir comment sens presque tous les fichiers, regardez la base de données derrière la commande file sur une machine UNIX, Linux ou Mac OS X.

file utilise une base de données de "nombres magiques" - ces octets initiaux Adam répertoriés - pour détecter le type d'un fichier. man file vous dira où trouver la base de données sur votre machine, par ex. /usr/share/file/magic. man magic vous dira format.

Vous pouvez écrire votre propre code de détection basé sur ce que vous voyez dans la base de données, utilisez les bibliothèques pré-emballés (par exemple python-magic), ou - si vous êtes vraiment aventureux - mettre en œuvre une version .NET de libmagic. Je n'ai pas pu en trouver un, et j'espère qu'un autre membre pourra en signaler un.

Si vous ne disposez pas d'une machine UNIX pratique, la base de données ressemble à ceci:

 
# 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 

Bonne chance!

2

Il existe une manière programmatique de déterminer l'image MIMETYPE. Il existe une classe System.Drawing.Imaging.ImageCodecInfo.

Cette classe a les propriétés MimeType et FormatID. En outre, il a une méthode GetImageEncoders qui retourne la collection de tous les encodeurs d'image. Il est facile de créer un dictionnaire de types MIME indexés par ID de format.

Classe System.Drawing.Image ont la propriété RawFormat de type System.Drawing.Imaging.ImageFormat qui ont la propriété Guid qui est équivalent de la propriété FormatID de classe System.Drawing. Imaging.ImageCodecInfo, et c'est la clé pour prendre MIMETYPE du dictionnaire.

Exemple:

Méthode statique pour créer le dictionnaire des 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; 
} 

Utilisation:

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

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

Vous pouvez utiliser le code ci-dessous sans distinction de System.Drawing et création inutile d'objet Image. Vous pouvez également utiliser la solution Alex même sans flux et référence de 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; 
} 
+0

Y at-il une séquence prévisible similaire pour pdf afin que nous puissions l'ajouter à cette liste? Merci – user95227

+1

@ utilisateur95227, oui! Voir cette lib: [Mime-Detective] (https://github.com/Muraad/Mime-Detective). La signature PDF est [ici] (https://github.com/Muraad/Mime-Detective/blob/master/MimeDetective/MimeTypes.cs#L47). –

Questions connexes