2008-09-11 18 views
42

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 pregunte) .Determine el tipo de archivo de una imagen

¿Cuál es la mejor forma 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 rompe todo el infierno.

Respuesta

51

Un enfoque probablemente más fácil sería utilizar Image.FromFile() y luego utilizar la propiedad RawFormat, como ya se sabe acerca de los bits de magia en las cabeceras de los formatos más comunes, como esto:

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

FYI, esto también funciona para los flujos utilizando System.Drawing.Image.FromStream() – jishi

+0

si estás en el contexto de una aplicación web, es importante utilizar el nombre completo o importar el montaje para evitar confusión con un control de imagen ... System.Drawing.Image – MacGyver

0

Intente cargar la secuencia en un 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 el PNG specifications

Agregado: El actual file structure para PNG.

21

Todos los formatos de imagen fijan sus bytes iniciales a un valor particular:

Búsqueda de "formato de archivo JPG "reemplazando jpg con otros formatos de archivo que necesita identificar.

Como Garth recomienda, hay un database of such 'magic numbers' 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 file command 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)

- Adam

8

Adam está apuntando en la dirección correcta.

Si usted quiere encontrar la manera de sentido casi cualquier archivo, mirar a la base de datos detrás del comando file en una máquina UNIX, Linux o Mac OS X.

file usa una base de datos de "números mágicos" - los 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, p. /usr/share/file/magic. man magic le dirá que es format.

Usted puede escribir su propio código de detección en base a lo que se ve en la base de datos, utilice bibliotecas pre-envasados ​​(por ejemplo python-magic), o - si está realmente aventurero - aplicar una versión .NET de libmagic. No pude encontrar uno, y espero que otro miembro pueda señalar uno.

En caso de que usted no tiene una máquina UNIX a mano, la base de datos tiene el siguiente aspecto:

 
# 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 

Buena suerte!

2

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 el diccionario de los tipos de mime indexados por ID de formato.

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

Ejemplo:

método estático para crear el diccionario de tipos 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; 
} 

Uso:

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

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

Puede utilizar el código de abajo sin referencia de System.Drawing y la creación innecesaria de objetos Imagen. También puede usar la solución Alex incluso sin secuencia y referencia 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

¿hay una secuencia predecible similar para el pdf para que podamos agregarlo a esta lista? Gracias – user95227

+1

@ user95227, sí! Vea esta lib: [Mime-Detective] (https://github.com/Muraad/Mime-Detective). La firma PDF es [aquí] (https://github.com/Muraad/Mime-Detective/blob/master/MimeDetective/MimeTypes.cs#L47). –

Cuestiones relacionadas