Determinar o tipo de arquivo de uma imagem
-
09-06-2019 - |
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.
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:
- JPG: 0xFF 0xD8
- PNG: 0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A
- GIFs: 'G' 'Eu' 'F'
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.