2009-08-07 18 views
8

Gibt es eine Möglichkeit herauszufinden, was der ContentType eines Bildes nur von den ursprünglichen Bytes ist?Herausfinden des ContentType eines Bildes aus dem Byte []

Im Moment habe ich eine Datenbankspalte, die nur das Byte [] speichert, das ich verwende, um ein Bild auf einer Webseite anzuzeigen.

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

Ich könnte natürlich nur den ContentType in einer anderen Spalte in der Tabelle speichern, sondern nur gefragt, ob es einen anderen Weg gab, z. vielleicht .Net hat eine Möglichkeit, die Daten abzufragen, um den Typ zu erhalten.

Antwort

15

Überprüfen Sie diese file signatures table.

+0

+1 Schöne Antwort. –

+0

Prost für den Link. Ich habe ein wenig gesucht, jetzt weiß ich, wonach ich suchen soll und das scheint der richtige Weg zu sein. –

+0

Ich habe eine funktionierende Version des folgenden Codes basierend auf Ihrer Idee erstellt. –

0

Funktioniert die RawFormat Eigenschaft für Sie?

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

RawFormat scheint für JPEG und GIF zu funktionieren, aber nicht für PNG. Für einen Test habe ich auch versucht, es zu jpeg zu kodieren und das funktionierte genauso (für alle und nicht png), ich denke, .Net wendet mehr Logik auf png an. –

+0

Von anderen Beispielen, die ich gesehen habe, scheint RawFormat nur zu funktionieren, wenn das Bild aus dem Dateisystem geladen wurde und nicht über Bytes (db-Spalte) erstellt wurde. –

1

Es gibt keine Standardmethode zum Erkennen von Inhaltstyp aus einem integrierten .NET-Stream. Sie könnten Ihren eigenen Algorithmus implementieren, der dies für einige well-known Bildformate erreichen könnte, indem Sie die ersten paar Bytes lesen und versuchen, das Format anzupassen.

14

Datei/magische Unterschriften war der Weg zu gehen. Unten ist die funktionierende Version des Codes.

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

Und dann die Hilfsklasse:

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

Aus Neugier, gibt es einen Grund, warum Ihre Schleifen mit "i + = 1" anstelle von "i ++" inkrementieren? – Portman

+0

Ich habe den Code von einer anderen Stackoverflow-Frage/Antwort (oben erwähnt) angepasst. Der Code hat sich seitdem geändert, da ich auch i ++ mehr verstehe als i + = 1. –

+0

@ Portman, persönliche Stile und Vorlieben. Manche Leute denken, dass 'i ++' klarer ist, andere denken, dass es weniger "Best Practice" ist. Siehe hierzu: http://stackoverflow.com/questions/971312/why-avoid-increment-and-decrement-operators-in-javascript – ANeves

6

Das ist für mich gearbeitet, ms die Memorystream zu sein. Der Nachteil ist, dass das Bild geladen werden muss.

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

schreibt die Methode von Nick Clarke ein bisschen mit 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 } 
    }; 
} 

I ImagePartType verwendet, weil ich im Moment mit Open XML SDK arbeiten bin, sondern nur die Art ändern, in dem Wörterbuch:)

Verwandte Themen