2009-08-07 15 views
8

¿Hay alguna forma de averiguar cuál es el ContentType de una imagen solo de los bytes originales?Encontrar el ContentType de una imagen del byte []

Por el momento tengo una columna de base de datos que almacena solo el byte [], que utilizo para mostrar una imagen en una página web.

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

Podría, por supuesto, simplemente guardar el ContentType en otra columna de la tabla, pero sólo se preguntó si había otra manera, por ejemplo, tal vez .Net tiene una forma de interrogar los datos para obtener el tipo.

Respuesta

15

Echa un vistazo a este file signatures table.

+0

+1 Buena respuesta. –

+0

Saludos por el enlace. Hice un poco de búsqueda, ahora sé qué buscar y este parece el camino a seguir. –

+0

He puesto una versión funcional del código a continuación, basada en su idea. –

0

¿La propiedad RawFormat funciona para usted?

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

RawFormat parece funcionar para jpeg y gif pero no png. Para una prueba también intenté codificarlo en JPEG y esto funcionó igual (para todos y no png), supongo que .Net aplica más lógica a png. –

+0

De otros ejemplos que he visto RawFormat parece funcionar solo cuando la imagen se cargó desde el sistema de archivos y no se creó a través de bytes (columna db). –

1

No hay una manera estándar de detectar el tipo de contenido de una secuencia de comandos incorporada .NET. Puede implementar su propio algoritmo que podría lograr esto para algunos formatos de imagen well-known leyendo los primeros bytes e intentando hacer coincidir el formato.

14

File/magic firts era el camino a seguir. A continuación está la versión de trabajo del código.

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

Y entonces la clase de ayuda:

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

Por curiosidad, ¿hay algún motivo por el que sus bucles incrementen con "i + = 1" en lugar de "i ++"? – Portman

+0

He adaptado el código de otra pregunta/respuesta Stackoverflow (mencionado anteriormente). El código ha cambiado ya que también entiendo i ++ más que i + = 1. –

+0

@Portman, estilos personales y preferencias. Algunas personas piensan que 'i ++' es más claro, otros piensan que es menos "mejor práctica". Vea esto: http://stackoverflow.com/questions/971312/why-avoid-increment-and-decrement-operators-in-javascript – ANeves

6

Esto funcionó para mí, ser ms MemoryStream. El inconveniente es que tiene que cargar la imagen.

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

Reescribir el método de Nick Clarke un poco usando 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 } 
    }; 
} 

Solía ​​ImagePartType porque estoy trabajando con el SDK de XML abierto en este momento, pero sólo cambiar el tipo en el diccionario:)

Cuestiones relacionadas