Determinar el tipo de archivo de una imagen

Estoy descargando algunas imágenes de un servicio que no siempre incluye un tipo de contenido y no proporciona una extensión para el archivo que estoy descargando (uf, no preguntes).

¿Cuál es la mejor manera de determinar el formato de imagen en .NET?

La aplicación que está leyendo estas imágenes descargadas debe tener una extensión de archivo adecuada o se desata todo el infierno.

Un enfoque probablemente más fácil sería usar Image.FromFile () y luego usar la propiedad RawFormat, ya que ya conoce los bits mágicos en los encabezados para los formatos más comunes, como este:

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 

Todos los formatos de imagen establecen sus bytes iniciales en un valor particular:

  • JPG: 0xFF 0xD8
  • PNG: 0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A
  • GIF: ‘G’ ‘I’ ‘F’

Busque “formato de archivo jpg” reemplazando jpg con los otros formatos de archivo que necesita identificar.

Como recomienda Garth, hay una base de datos de tales ‘números mágicos’ que muestra el tipo de archivo de muchos archivos. Si tiene que detectar una gran cantidad de tipos de archivos diferentes, vale la pena mirar para encontrar la información que necesita. Si necesita extender esto para cubrir muchos, muchos tipos de archivos, mire el comando de archivo asociado que implementa el motor para usar la base de datos correctamente (no es trivial para muchos formatos de archivo, y es casi un proceso estadístico)

-Adán

Puede usar el código a continuación sin referencia de System.Drawing y creación innecesaria de objeto Image. También puede usar la solución Alex incluso sin transmisión y referencia de System.IO.

 public enum ImageFormat { bmp, jpeg, gif, tiff, png, unknown } public static ImageFormat GetImageFormat(Stream stream) { // see http://sofes.miximages.com/.net/ 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; } 

Adam señala en la dirección correcta.

Si desea descubrir cómo detectar casi cualquier archivo , mire la base de datos detrás del comando de file en una máquina UNIX, Linux o Mac OS X.

file usa una base de datos de “números mágicos” – esos bytes iniciales que Adam mencionó – para detectar el tipo de un archivo. man file le dirá dónde encontrar la base de datos en su máquina, por ejemplo /usr/share/file/magic . man magic te dirá su formato .

Puede escribir su propio código de detección según lo que ve en la base de datos, usar bibliotecas preempaquetadas (por ejemplo, python-magic ) o, si es realmente aventurero, implementar una versión .NET de libmagic . No pude encontrar uno, y espero que otro miembro pueda señalar uno.

En caso de que no tenga una máquina UNIX a mano, la base de datos se ve así:

 # PNG [Gráficos de red portátiles, o "PNG's Not GIF"] imágenes
 # (Greg Roelofs, newt@uchicago.edu)
 # (Albert Cahalan, acahalan@cs.uml.edu)
 #
 # 137 PNG \ r \ n ^ Z \ n [longitud de 4 bytes] HEAD [HEAD data] [HEAD crc] ...
 #
 0 string \ x89PNG PNG image data,
 > 4 pertenecen! 0x0d0a1a0a CORRUPTADO,
 > 4 pertenecen 0x0d0a1a0a
 >> 16 pertenecen x% ld x
 >> 20 pertenecen x% ld,
 >> 24 byte x% d-bit
 >> 25 bytes 0 en escala de grises,
 >> 25 byte 2 \ b / color RGB,
 >> 25 byte 3 colormap,
 >> 25 byte 4 gris + alfa,
 >> 25 byte 6 \ b / color RGBA,
 # >> 26 byte 0 deflate / 32K,
 >> 28 byte 0 sin entrelazar
 >> 28 byte 1 entrelazado
 Datos de imagen PNG PNG de 1 cadena, CORRUPTED

 # GIF
 0 cadena de datos de imagen GIF8 GIF
 > 4 cuerdas 7a \ b, versión 8% s,
 > 4 cuerdas 9a \ b, versión 8% s,
 > 6 leshort> 0% hd x
 > 8 leshort> 0% hd
 #> 10 bytes y 0x80 colores mapeados,
 #> 10 byte y 0x07 = 0x00 2 colores
 #> 10 byte y 0x07 = 0x01 4 colores
 #> 10 byte y 0x07 = 0x02 8 colores
 #> 10 byte y 0x07 = 0x03 16 colores
 #> 10 byte y 0x07 = 0x04 32 colores
 #> 10 byte y 0x07 = 0x05 64 colores
 #> 10 byte y 0x07 = 0x06 128 colores
 #> 10 byte y 0x07 = 0x07 256 colores

¡Buena suerte!

Hay una forma programática para determinar la imagen MIMETYPE.

Hay clase System.Drawing.Imaging.ImageCodecInfo .

Esta clase tiene propiedades MimeType y FormatID . También tiene un método GetImageEncoders que devuelve la colección de todos los codificadores de imagen. Es fácil crear Diccionario de tipos mime indexados por ID de formato.

Class System.Drawing.Image tiene la propiedad RawFormat de Type System.Drawing.Imaging.ImageFormat que tiene la propiedad Guid que es equivalente a la propiedad FormatID de la clase System.Drawing.Imaging.ImageCodecInfo , y esa es la clave para tomar MIMETYPE del diccionario.

Ejemplo:

Método estático para crear diccionarios de tipos de mime

 static Dictionary GetImageFormatMimeTypeIndex() { Dictionary ret = new Dictionary(); var encoders = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders(); foreach(var e in encoders) { ret.Add(e.FormatID, e.MimeType); } return ret; } 

Utilizar:

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

Intente cargar la secuencia en System.IO.BinaryReader.

Luego deberá consultar las especificaciones para cada formato de imagen que necesite, y cargar el byte del encabezado por byte para compararlo con las especificaciones. Por ejemplo, aquí están las especificaciones PNG

Agregado: la estructura de archivo real para PNG.