Determina il tipo di file di un'immagine
-
09-06-2019 - |
Domanda
Sto scaricando alcune immagini da un servizio che non sempre include un tipo di contenuto e non fornisce un'estensione per il file che sto scaricando (ugh, non chiedere).
Qual è il modo migliore per determinare il formato dell'immagine in .NET?
L'applicazione che legge queste immagini scaricate deve avere un'estensione di file corretta altrimenti si scatenerà l'inferno.
Soluzione
Un approccio probabilmente più semplice sarebbe quello di utilizzare Image.FromFile() e quindi utilizzare la proprietà RawFormat, poiché conosce già i bit magici nelle intestazioni per i formati più comuni, come questo:
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
Altri suggerimenti
Tutti i formati di immagine impostano i loro byte iniziali su un valore particolare:
- JPG: 0xFF 0xD8
- PNG: 0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A
- GIF: 'G' 'I' 'F'
Cerca "formato file jpg" sostituendo jpg con gli altri formati di file che devi identificare.
Come consiglia Garth, esiste un database di tali "numeri magici" mostrando il tipo di file di molti file.Se devi rilevare molti tipi di file diversi, vale la pena esaminarli per trovare le informazioni di cui hai bisogno.Se hai bisogno di estenderlo per coprire molti, molti tipi di file, guarda il file associato comando di file che implementa il motore per utilizzare correttamente il database (non è banale per molti formati di file ed è quasi un processo statistico)
-Adamo
È possibile utilizzare il codice seguente senza riferimento a System.Drawing e alla creazione non necessaria dell'oggetto Image.Inoltre puoi usare Alex soluzione anche senza stream e riferimento di 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 sta puntando esattamente nella direzione giusta.
Se vuoi scoprire come fare percepire quasi tutti i file, guarda il database dietro il file
comando su una macchina UNIX, Linux o Mac OS X.
file
utilizza un database di "numeri magici" - quei byte iniziali elencati da Adam - per rilevare il tipo di file. man file
ti dirà dove trovare il database sul tuo computer, ad es. /usr/share/file/magic
. man magic
ti dirà la sua formato.
Puoi scrivere il tuo codice di rilevamento in base a ciò che vedi nel database, utilizzare librerie preconfezionate (ad es. python-magico), o - se lo sei Veramente avventuroso: implementa una versione .NET di libmagic
.Non sono riuscito a trovarne uno e spero che un altro membro possa indicarne uno.
Nel caso in cui non hai una macchina UNIX a portata di mano, il database si presenta così:
# 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
Buona fortuna!
Esiste un modo programmatico per determinare il MIMETYPE dell'immagine.
C'è classe System.Drawing.Imaging.ImageCodecInfo.
Questa classe ha proprietà MimeType E ID formato.Inoltre ha un metodo GetImageEncoders che restituiscono la raccolta di tutti i codificatori di immagini.È facile creare un dizionario di tipi MIME indicizzati per ID formato.
Classe System.Drawing.Image avere proprietà Formato raw di Tipo System.Drawing.Imaging.ImageFormat che hanno proprietà Guida che equivale alla proprietà ID formato di classe System.Drawing.Imaging.ImageCodecInfo, e questa è la chiave per prendere MIMETYPE dal dizionario.
Esempio:
Metodo statico per creare dizionario di tipi 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;
}
Utilizzo:
Dictionary<Guid, string> mimeTypeIndex = GetImageFormatMimeTypeIndex();
FileStream imgStream = File.OpenRead(path);
var image = System.Drawing.Image.FromStream(imgStream);
string mimeType = mimeTypeIndex[image.RawFormat.Guid];
Prova a caricare il flusso in un System.IO.BinaryReader.
Quindi dovrai fare riferimento alle specifiche per ciascun formato di immagine di cui hai bisogno e caricare l'intestazione byte per byte per confrontarla con le specifiche.Ad esempio ecco i Specifiche PNG
Aggiunto:L'attuale struttura dei file per PNG.