2009-08-07 3 views
8

Existe-t-il un moyen de savoir quel est le ContentType d'une image provenant uniquement des octets d'origine?Connaître le ContentType d'une image à partir de l'octet []

Pour le moment j'ai une colonne de base de données qui stocke seulement l'octet [], que j'utilise pour afficher une image sur une page Web.

MemoryStream ms = new MemoryStream(imageBytes); 
Image image = Image.FromStream(ms); 
image.Save(context.HttpContext.Response.OutputStream, <--ContentType-->); 

Je pourrais bien sûr simplement enregistrer le ContentType dans une autre colonne dans la table, mais juste demandé s'il y avait une autre façon par exemple peut-être .Net a un moyen d'interroger les données pour obtenir le type.

Répondre

15

Consultez ce file signatures table.

+0

+1 Bonne réponse. –

+0

Bravo pour le lien. J'ai fait quelques recherches, maintenant je sais ce qu'il faut chercher et cela semble être le chemin à parcourir. –

+0

J'ai mis une version de travail du code ci-dessous, basée sur votre idée. –

0

Est-ce que la propriété RawFormat fonctionne pour vous?

MemoryStream ms = new MemoryStream(imageBytes); 
Image image = Image.FromStream(ms); 
image.Save(context.HttpContext.Response.OutputStream, image.RawFormat); 
+0

RawFormat semble fonctionner pour jpeg et gif mais pas png. Pour un test, j'ai aussi essayé de le coder en dur au format jpeg et cela a fonctionné de la même manière (pour tout le monde et pas pour le png), je suppose que .Net applique plus de logique au png. –

+0

D'autres exemples, j'ai vu RawFormat semble fonctionner uniquement lorsque l'image a été chargée à partir du système de fichiers et non créée via des octets (colonne db). –

1

Il n'existe aucun moyen standard pour détecter le type de contenu à partir d'un flux intégré .NET. Vous pouvez implémenter votre propre algorithme qui pourrait atteindre ceci pour certains formats d'image en lisant les premiers octets et en essayant de faire correspondre le format.

14

Le fichier/signatures magiques était la voie à suivre. Voici la version de travail du code.

Ref: Stackoverflow - Getting image dimensions without reading the entire file

ImageFormat contentType = ImageHelper.GetContentType(this.imageBytes); 

MemoryStream ms = new MemoryStream(this.imageBytes); 
Image image = Image.FromStream(ms); 
image.Save(context.HttpContext.Response.OutputStream, contentType); 

Et puis la classe d'aide:

public static class ImageHelper 
{ 
    public static ImageFormat GetContentType(byte[] imageBytes) 
    { 
     MemoryStream ms = new MemoryStream(imageBytes); 

     using (BinaryReader br = new BinaryReader(ms)) 
     { 
      int maxMagicBytesLength = imageFormatDecoders.Keys.OrderByDescending(x => x.Length).First().Length; 

      byte[] magicBytes = new byte[maxMagicBytesLength]; 

      for (int i = 0; i < maxMagicBytesLength; i += 1) 
      { 
       magicBytes[i] = br.ReadByte(); 

       foreach (var kvPair in imageFormatDecoders) 
       { 
        if (magicBytes.StartsWith(kvPair.Key)) 
        { 
         return kvPair.Value; 
        } 
       } 
      } 

      throw new ArgumentException("Could not recognise image format", "binaryReader"); 
     } 
    } 

    private static bool StartsWith(this byte[] thisBytes, byte[] thatBytes) 
    { 
     for (int i = 0; i < thatBytes.Length; i += 1) 
     { 
      if (thisBytes[i] != thatBytes[i]) 
      { 
       return false; 
      } 
     } 
     return true; 
    } 

    private static Dictionary<byte[], ImageFormat> imageFormatDecoders = new Dictionary<byte[], ImageFormat>() 
    { 
     { new byte[]{ 0x42, 0x4D }, ImageFormat.Bmp}, 
     { new byte[]{ 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, ImageFormat.Gif }, 
     { new byte[]{ 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, ImageFormat.Gif }, 
     { new byte[]{ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, ImageFormat.Png }, 
     { new byte[]{ 0xff, 0xd8 }, ImageFormat.Jpeg }, 
    }; 
+0

Par curiosité, y a-t-il une raison pour que vos boucles s'incrémentent avec "i + = 1" au lieu de "i ++"? – Portman

+0

J'ai adapté le code d'une autre question/réponse Stackoverflow (mentionnée ci-dessus). Le code a depuis changé car je comprends aussi i ++ plus de i + = 1. –

+0

@Portman, styles personnels et préférences. Certaines personnes pensent que «i ++» est plus clair, d'autres pensent que c'est moins «meilleure pratique». Voir ceci: http://stackoverflow.com/questions/971312/why-avoid-increment-and-decrement-operators-in-javascript – ANeves

6

Cela a fonctionné pour moi, ms étant MemoryStream. L'inconvénient est qu'il doit charger l'image.

Dim fmt As System.Drawing.Imaging.ImageFormat 
Dim content As String 

Using bmp As New Drawing.Bitmap(ms) 
    fmt = bmp.RawFormat 
End Using 

Select Case fmt.Guid 
    Case Drawing.Imaging.ImageFormat.Bmp.Guid 
     content = "image/x-ms-bmp" 

    Case Drawing.Imaging.ImageFormat.Jpeg.Guid 
     content = "image/jpeg" 

    Case Drawing.Imaging.ImageFormat.Gif.Guid 
     content = "image/gif" 

    Case Drawing.Imaging.ImageFormat.Png.Guid 
     content = "image/png" 

    Case Else 
     content = "application/octet-stream" 

End Select 
2

Réécriture de la méthode de Nick Clarke un peu LINQ:

public class Program 
{ 
    public static void Main(string[] args) 
    { 
     byte[] byteArray = File.ReadAllBytes(@"C:/users/Alexander/image.jpg"); 
     ImagePartType type = byteArray.GetImageType(); 
    } 
} 


public static class ImageHelper 
{ 
    public static ImagePartType GetImageType(this byte[] imageBytes) 
    { 
     foreach(var imageType in imageFormatDecoders) 
     { 
      if (imageType.Key.SequenceEqual(imageBytes.Take(imageType.Key.Length))) 
       return imageType.Value; 
     } 

     throw new ArgumentException("Imagetype is unknown!"); 
    } 

    private static Dictionary<byte[], ImagePartType> imageFormatDecoders 
        = new Dictionary<byte[], ImagePartType>() 
    { 
     { new byte[]{ 0x42, 0x4D }, ImagePartType.Bmp}, 
     { new byte[]{ 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, ImagePartType.Gif }, 
     { new byte[]{ 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, ImagePartType.Gif }, 
     { new byte[]{ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, ImagePartType.Png }, 
     { new byte[]{ 0xff, 0xd8 }, ImagePartType.Jpeg } 
    }; 
} 

je ImagePartType parce que je travaille avec Open XML SDK pour le moment, mais il suffit de changer le type dans le dictionnaire:

Questions connexes