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.

È stato utile?

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:

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top