.net - son - Determinar el tipo de archivo de una imagen
que son los archivos de imagen (6)
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.
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 format .
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 [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!
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<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;
}
Utilizar:
Dictionary<Guid, string> 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.
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://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;
}
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
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