Pergunta

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 o inferno desabou.

Foi útil?

Solução

Uma abordagem provavelmente mais fácil seria usar Image.FromFile() e depois usar a propriedade RawFormat, pois ela já conhece os bits mágicos nos cabeçalhos dos 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

Outras dicas

Todos os formatos de imagem definem seus bytes iniciais com um valor específico:

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

Como recomenda Garth, há uma banco de dados de tais 'números mágicos' mostrando o tipo de arquivo de muitos arquivos.Se você precisar detectar muitos tipos de arquivos diferentes, vale a pena examiná-los para encontrar as informações necessárias.Se você precisar estender isso para cobrir muitos tipos de arquivos, consulte o arquivo associado comando de arquivo que implementa o mecanismo para usar o banco de dados 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 do objeto Image.Você também pode usar Alex solução 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://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;
}

Adam está apontando exatamente na direção certa.

Se você quiser descobrir como sinta quase qualquer arquivo, observe o banco de dados por trás do file comando em uma máquina UNIX, Linux ou Mac OS X.

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

Você pode escrever seu próprio código de detecção com base no que vê no banco de dados, usar bibliotecas pré-empacotadas (por exemplo, magia python) ou - se você estiver realmente aventureiro - implemente uma versão .NET do libmagic.Não consegui encontrar um e espero que outro membro possa apontar um.

Caso você não tenha uma máquina UNIX em mãos, o banco de dados ficará assim:

# PNG [Portable Network Graphics, or "PNG's Not GIF"] images
# (Greg Roelofs, newt@uchicago.edu)
# (Albert Cahalan, acahalan@cs.uml.edu)
#
# 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

Boa sorte!

Existe uma maneira programática de determinar o MIMETYPE da imagem.

Há aula System.Drawing.Imaging.ImageCodecInfo.

Esta classe tem propriedades MimeType e ID do formato.Também tem um método GetImageEncoders que retornam a coleção de todos os codificadores de imagem.É fácil criar dicionário de tipos MIME indexados por ID de formato.

Aula Sistema.Desenho.Imagem ter propriedade Formato bruto do tipo System.Drawing.Imaging.ImageFormat que possuem propriedade Guia que é equivalente à propriedade ID do formato de aula System.Drawing.Imaging.ImageCodecInfo, e isso é a chave para obter MIMETYPE do dicionário.

Exemplo:

Método estático para criar dicionário 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;
}

Usar:

Dictionary<Guid, string> 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 de cada formato de imagem necessário e carregar o cabeçalho byte por byte para comparar com as especificações.Por exemplo, aqui estão os Especificações PNG

Adicionado:O real estrutura de arquivo para PNG.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top