2009-04-21 13 views

Respuesta

94

Varias opciones (El enlace es a una entrada de blog de Raymond Chen.):

puede comprobar si la extensión del archivo:

static bool HasJpegExtension(string filename) 
{ 
    // add other possible extensions here 
    return Path.GetExtension(filename).Equals(".jpg", StringComparison.InvariantCultureIgnoreCase) 
     || Path.GetExtension(filename).Equals(".jpeg", StringComparison.InvariantCultureIgnoreCase); 
} 

o detectar la correcta magic number en la cabecera del archivo:

static bool HasJpegHeader(string filename) 
{ 
    using (BinaryReader br = new BinaryReader(File.Open(filename, FileMode.Open, FileAccess.Read))) 
    { 
     UInt16 soi = br.ReadUInt16(); // Start of Image (SOI) marker (FFD8) 
     UInt16 marker = br.ReadUInt16(); // JFIF marker (FFE0) or EXIF marker(FF01) 

     return soi == 0xd8ff && (marker & 0xe0ff) == 0xe0ff; 
    } 
} 

Otra opción sería la de cargar la imagen y comprobar el tipo correcto. Sin embargo, esto es menos eficiente (a menos que cargue la imagen de todos modos) pero probablemente le dará el resultado más confiable (tenga en cuenta el costo adicional de carga y descompresión, así como el posible manejo de excepciones):

static bool IsJpegImage(string filename) 
{ 
    try 
    { 
     using (System.Drawing.Image img = System.Drawing.Image.FromFile(filename)) 
     {   
      // Two image formats can be compared using the Equals method 
      // See http://msdn.microsoft.com/en-us/library/system.drawing.imaging.imageformat.aspx 
      // 
      return img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Jpeg); 
     } 
    } 
    catch (OutOfMemoryException) 
    { 
     // Image.FromFile throws an OutOfMemoryException 
     // if the file does not have a valid image format or 
     // GDI+ does not support the pixel format of the file. 
     // 
     return false; 
    } 
} 
+1

+1 por ser más diligente. Un par de ideas: cambiaría el nombre a HasJpegExtension y ContainsJpegHeader. Además, ¿no le gustaría capturar otras excepciones en caso de que el archivo se haya eliminado/movido/etc entre la comprobación de la ext/encabezado y tratando de cargarlo? o sería mejor simplemente hacerles burbujas a todos? –

+0

Seguramente el nombre puede mejorarse y debe ajustarse a su caso de uso real. En este simple ejemplo, simplemente elijo agregar la forma específica utilizada como sufijo. Al final, probablemente usaría 'IsJpeg' o algunas de sus sugerencias. Como es un ejemplo simple, no quería sobrecargarlo con manejo de excepciones, pero normalmente manejaba excepciones relacionadas con el archivo io y permisos de acceso más arriba en la pila. –

+1

En la función HasJpegHeader anterior, estoy de acuerdo con el FF D8, pero no siempre es FF E0. A veces es FF E1. Por lo tanto, la función anterior dio como resultado FALSE para un archivo JPG correcto. – Ruturaaj

4

Puede encontrar documentación sobre el formato de archivo jpeg, específicamente la información del encabezado. Luego intente leer esta información del archivo y compárela con los bytes del encabezado jpeg esperados.

0

El código aquí:

http://mark.michaelis.net/Blog/RetrievingMetaDataFromJPEGFilesUsingC.aspx

que muestra cómo obtener los metadatos. Supongo que arrojaría una excepción si su imagen no era un JPEG válido.

+0

Su respuesta es un ejemplo clásico de por qué _unly_ enlaces no deberían darse como respuesta. La página ya no está y la respuesta es inútil ahora. Si puede improvisar su respuesta, sería genial o si no, debería eliminarse o marcarse para su eliminación. – Mrchief

+0

Es una delgada línea entre tomar el contenido de otros y permitir suficientes créditos/visitas al material original. Elegí dar crédito a la fuente. El problema aquí es que el usuario al que se hace referencia no proporciona un redireccionamiento a la nueva ubicación o incluso un "Desaparecido". –

+0

Sí, estoy de acuerdo en parte contigo. Es necesario acreditar la fuente y lo ha hecho al incluir el enlace. Desafortunadamente, SO no es un lugar para simplemente acreditar a otros, está destinado a proporcionar respuestas y eso es precisamente lo que falta aquí. La respuesta aceptada y la respuesta de @simongibbs son un buen ejemplo de cómo hacer ambas cosas y hay muchas otras en SO que podría usar como referencia. Como dijiste, porque los 404 son una dura realidad y no puedes esperar que todos devuelvan un 302, incluyendo una esencia que es útil y muy necesaria. – Mrchief

1

Una vez que tenga la extensión, puede usar una expresión regular para validarla.

^.*\.(jpg|JPG)$ 
+5

Debe incluir 'jpeg' también, y probablemente pasar un minuto buscando otras extensiones de archivo jpeg menos comunes. –

28

Abra el archivo como una secuencia y busque el magic number para JPEG.

Los archivos de imagen JPEG comienzan con FF D8 y terminan con FF D9. Los archivos JPEG/JFIF contienen el código ASCII para 'JFIF' (4A 46 49 46) como una cadena terminada nula. archivos JPEG/Exif contienen el código ASCII para 'Exif' (45 78 69 66) también como un nulo cadena terminada

+0

Esto, por supuesto, no es en absoluto un control confiable, ya que es trivial crear un archivo que no sea jpeg que cumpla con estas condiciones. – jarnbjo

+0

Creo que es proporcional al grueso de los casos de uso. Claro que hay posibles problemas de seguridad/DoS al aceptar un formato que no es JPEG, pero esa es otra pregunta, creo ;-) –

12

Usted podría intentar cargar el archivo en una imagen y luego comprobar el formato

Image img = Image.FromFile(filePath); 
bool isBitmap = img.RawFormat.Equals(ImageFormat.Jpeg); 

alternativamente, puede abrir el archivo y comprobar el encabezado para obtener el tipo

+1

Para cada caso positivo, habría decodificado toda la imagen cuando no lo deseara, y para cada caso negativo Espero que tengas que manejar una excepción: conducir al pobre tipo para depurar tu código mentalmente en F5. Supongo que depende del escenario, pero hay otras respuestas que no tienen estos problemas. –

+0

La comparación realmente falla. Necesita llamar 'ImageFormat.Equals' en lugar de usar el operador' == '. –

+0

Corregí el error en el código. –

0

Comprobación de la extensión del archivo no es suficiente, ya que el nombre del archivo podría estar mintiendo.

Una manera rápida y sucia es tratar de cargar la imagen utilizando la clase de imagen y la captura de las excepciones:

Image image = Image.FromFile(@"c:\temp\test.jpg"); 

Esto no es ideal ya que se podía conseguir cualquier tipo de excepción, tales como OutOfMemoryException, FileNotFoundException, etc. etc.

La forma más completa es tratar el archivo como binario y asegurarse de que el encabezado coincida con el formato JPG. Estoy seguro de que está descrito en alguna parte.

0

La mejor manera sería tratar de crear una imagen a partir de ella utilizando el constructor Drawing.Bitmap (cadena) y ver si no puede hacerlo o lanza una excepción. El problema con algunas de las respuestas es este: en primer lugar, la extensión es puramente arbitraria, podría ser jpg, jpeg, jpe, bob, tim, lo que sea. En segundo lugar, solo usar el encabezado no es suficiente para estar 100% seguro.Definitivamente puede determinar que un archivo no es un jpeg, pero no puede garantizar que un archivo sea un jpeg, un archivo binario arbitrario podría tener la misma secuencia de bytes al inicio.

1

Esto recorrerá cada archivo en el directorio actual y saldrá si los archivos encontrados con extensión JPG o JPEG son imágenes JPEG.

 foreach (FileInfo f in new DirectoryInfo(".").GetFiles()) 
     { 
      if (f.Extension.ToUpperInvariant() == ".JPG" 
       || f.Extension.ToUpperInvariant() == ".JPEG") 
      { 
       Image image = Image.FromFile(f.FullName); 

       if (image.RawFormat == ImageFormat.Jpeg) 
       { 
        Console.WriteLine(f.FullName + " is a Jpeg image"); 
       } 
      } 
     } 
24

OMG, muchos de estos ejemplos de código son incorrectos, incorrectos.

archivos EXIF ​​tener un marcador de 0xff * E1 *, JFIF archivos tienen un marcador de 0xff * e0 *. Por lo tanto, todo el código que se basa en 0xffe0 para detectar un archivo JPEG perderá todos los archivos EXIF.

Aquí hay una versión que detectará ambas cosas, y puede modificarse fácilmente para que solo regrese para JFIF o solo para EXIF. (Útil al tratar de recuperar las imágenes de su iPhone, por ejemplo).

public static bool HasJpegHeader(string filename) 
    { 
     try 
     { 
      // 0000000: ffd8 ffe0 0010 4a46 4946 0001 0101 0048 ......JFIF.....H 
      // 0000000: ffd8 ffe1 14f8 4578 6966 0000 4d4d 002a ......Exif..MM.*  
      using (BinaryReader br = new BinaryReader(File.Open(filename, FileMode.Open, FileAccess.ReadWrite))) 
      { 
       UInt16 soi = br.ReadUInt16(); // Start of Image (SOI) marker (FFD8) 
       UInt16 marker = br.ReadUInt16(); // JFIF marker (FFE0) EXIF marker (FFE1) 
       UInt16 markerSize = br.ReadUInt16(); // size of marker data (incl. marker) 
       UInt32 four = br.ReadUInt32(); // JFIF 0x4649464a or Exif 0x66697845 

       Boolean isJpeg = soi == 0xd8ff && (marker & 0xe0ff) == 0xe0ff; 
       Boolean isExif = isJpeg && four == 0x66697845; 
       Boolean isJfif = isJpeg && four == 0x4649464a; 

       if (isJpeg) 
       { 
        if (isExif) 
         Console.WriteLine("EXIF: {0}", filename); 
        else if (isJfif) 
         Console.WriteLine("JFIF: {0}", filename); 
        else 
         Console.WriteLine("JPEG: {0}", filename); 
       } 

       return isJpeg; 
       return isJfif; 
       return isExif; 
      } 
     } 
     catch 
     { 
      return false; 
     } 
    } 
+0

Wikipedia muestra que el hex para JPEG/JFIF es '4A 46 49 46', pero está buscando' 0x4649464a'. EXIF es '45 78 69 66', pero está buscando' 0x66697845'. Supongo que su código es correcto, pero ¿por qué están al revés? – vaindil

+2

@vaindil Estaba tan completamente a punto de troll, pero luego me di cuenta de que en realidad habías ido a Wikipedia e hiciste tu propia investigación, y notado no solo que los números eran diferentes, sino que en realidad estaban al revés. Entonces responderé tu pregunta. La respuesta es [Endianness] (https://en.wikipedia.org/wiki/Endianness). Si no desea leer otro artículo de wikipedia, la versión TL; DR es: ** Las máquinas Intel almacenan valores en la memoria al revés **. – Orwellophile

+0

@Orwellophile Oh wow, ni siquiera pensé en endianness. -_- Lo sé, por alguna razón, ni siquiera se me pasó por la cabeza. ¡Gracias lo aprecio! – vaindil

0

Simplemente tome el tipo de medio del archivo y verificar:

private bool isJpeg() 
     { 
string p = currFile.Headers.ContentType.MediaType; 
      return p.ToLower().Equals("image/jpeg") || p.ToLower().Equals("image/pjpeg") || p.ToLower().Equals("image/png"); 
     } 
0

después del check extensión de archivo de leer cuatro primeros bytes de la imagen y dos último byte de la imagen como esta, que lo haga por dos último byte por valor de 255, 217 de otro archivo puede hacerlo Validate image from file in C# http://www.garykessler.net/library/file_sigs.html

// after check extention of file 
byte[] ValidFileSignture = new byte[] { 255, 216, 255, 224 }; 
byte[] bufferforCheck = new byte[ValidFileSignture.Length]; 
Stream _inputStream = file.InputStream; 
byte[] bufferforCheck1 = new byte[] { 255, 216, 255, 224 }; 
_inputStream.Read(bufferforCheck, 0, ValidFileSignture.Length); 
if (!Enumerable.SequenceEqual(bufferforCheck, ValidFileSignture)) 
{ 
    //file OK 
} 
0
System.Web.MimeMapping.GetMimeMapping(filename).StartsWith("image/"); 
MimeMapping.GetMimeMapping produces these results: 

file.jpg: image/jpeg 
file.gif: image/gif 
file.jpeg: image/jpeg 
file.png: image/png 
file.bmp: image/bmp 
file.tiff: image/tiff 
file.svg: application/octet-stream 
Cuestiones relacionadas