Determinar o tipo de arquivo de uma imagem

Estou baixando algumas imagens de um serviço que nem sempre inclui um tipo de conteúdo e não fornece uma extensão para o arquivo que estou baixando (ugh, não pergunte).

Qual é a melhor maneira de determinar o formato da imagem no .NET?

O aplicativo que está lendo essas imagens baixadas precisa ter uma extensão de arquivo adequada ou todo o inferno se solta.

Uma abordagem provavelmente mais fácil seria usar Image.FromFile () e depois usar a propriedade RawFormat, já que ela já sabe sobre os bits mágicos nos headers para os formatos mais comuns, 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 os formatos de imagem definem seus bytes iniciais para um valor específico:

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

Procure por “formato de arquivo jpg” substituindo jpg por outros formatos de arquivo que você precisa identificar.

Como Garth recomenda, há um database de tais ‘números mágicos’ mostrando o tipo de arquivo de muitos arquivos. Se você precisar detectar muitos tipos diferentes de arquivos, vale a pena pesquisar as informações necessárias. Se você precisar estender isso para abranger muitos, muitos tipos de arquivos, veja o comando de arquivo associado que implementa o mecanismo para usar o database corretamente (não é trivial para muitos formatos de arquivo e é quase um processo estatístico)

-Adão

Você pode usar o código abaixo sem referência de System.Drawing e criação desnecessária de object Image. Além disso, você pode usar a solução Alex , mesmo sem stream e referência de System.IO.

 public enum ImageFormat { bmp, jpeg, gif, tiff, png, unknown } public static ImageFormat GetImageFormat(Stream stream) { // see http://sofpt.miximages.com/content-type/ 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 está apontando exatamente na direção certa.

Se você quiser descobrir como detectar quase todos os arquivos , consulte o database por trás do comando file em uma máquina UNIX, Linux ou Mac OS X.

file usa um database de “números mágicos” – aqueles bytes iniciais que Adam listou – para detectar o tipo de um arquivo. man file lhe dirá onde encontrar o database em sua máquina, por exemplo /usr/share/file/magic . man magic lhe dirá seu formato .

Você pode escrever seu próprio código de detecção baseado no que você vê no database, usar bibliotecas pré-empacotadas (por exemplo, python-magic ), ou – se você for realmente aventureiro – implementar uma versão .NET do libmagic . Eu não consegui encontrar um, e espero que outro membro possa apontar um para fora.

Caso você não tenha uma máquina UNIX à mão, o database se parece com isto:

 # PNG [Imagens de rede portáteis ou "PNG não GIF"]
 # (Greg Roelofs, newt@uchicago.edu)
 # (Albert Cahalan, acahalan@cs.uml.edu)
 #
 # 137 PNG \ r \ n ^ Z \ n [comprimento de 4 bytes] HEAD [HEAD data] [HEAD crc] ...
 #
 0 string \ x89PNG dados de imagem PNG,
 > 4 pertencem! 0x0d0a1a0a CORROMPIDO,
 > 4 pertencem 0x0d0a1a0a
 >> 16 pertencem x% ld x
 >> 20 pertencem x% ld,
 >> 24 byte x% d-bit
 >> 25 bytes em escala de cinza,
 >> 25 bytes 2 \ b / cor RGB,
 >> 25 byte 3 colormap,
 >> 25 byte 4 cinza + alfa,
 >> 25 byte 6 \ b / cor RGBA,
 # >> 26 byte 0 deflate / 32K,
 >> 28 byte 0 não entrelaçado
 >> 28 byte 1 entrelaçado
 1 string PNG PNG image data, CORRUPTED

 # GIF
 0 string GIF8 GIF image data
 > 4 string 7a \ b, versão 8% s,
 > 4 cordas 9a \ b, versão 8% s,
 > 6 leshort> 0% hd x
 > 8 leshort> 0% hd
 #> 10 bytes e cor 0x80 mapeados
 #> 10 byte e 0x07 = 0x00 2 colors
 #> 10 bytes e 0x07 = 0x01 4 colors
 #> 10 bytes e 0x07 = 0x02 8 colors
 #> 10 bytes e 0x07 = 0x03 16 colors
 #> 10 bytes e 0x07 = 0x04 32 colors
 #> 10 bytes e 0x07 = 0x05 64 colors
 #> 10 bytes e 0x07 = 0x06 128 colors
 #> 10 bytes e 0x07 = 0x07 256 colors

Boa sorte!

Existe uma maneira programática de determinar a imagem MIMETYPE.

Existe class System.Drawing.Imaging.ImageCodecInfo .

Esta class tem propriedades MimeType e FormatID . Também tem um método GetImageEncoders que retorna a coleção de todos os codificadores de imagem. É fácil criar um dictionary de tipos mime indexados por id de formato.

A class System.Drawing.Image tem a propriedade RawFormat do tipo System.Drawing.Imaging.ImageFormat que possui a propriedade Guid que é equivalente à propriedade FormatID da class System.Drawing.Imaging.ImageCodecInfo e é a chave para obter o MIMETYPE do dictionary.

Exemplo:

Método estático para criar dictionary de tipos 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; } 

Usar:

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

Tente carregar o stream em um System.IO.BinaryReader.

Em seguida, você precisará consultar as especificações para cada formato de imagem necessário e carregar o byte de header por byte para comparar com as especificações. Por exemplo, aqui estão as especificações do PNG

Adicionado: a estrutura real do arquivo para PNG.