35

Using C# how can I test a file is a jpeg? Should I check for a .jpg extension?

Thanks

16 Answers16

107

Several options:

You can check for the file extension:

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);
}

or check for the correct magic number in the header of the file:

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(FFE1)

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

Another option would be to load the image and check for the correct type. However, this is less efficient (unless you are going to load the image anyway) but will probably give you the most reliable result (Be aware of the additional cost of loading and decompression as well as possible exception handling):

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;
    }
}
HanClinto
  • 9,423
  • 3
  • 30
  • 31
Dirk Vollmar
  • 172,527
  • 53
  • 255
  • 316
  • 1
    +1 for being more diligent. Couple of ideas: I would rename to HasJpegExtension and ContainsJpegHeader. Also,wouldn't you want catch other exceptions in case the file was deleted/moved/etc between checking the ext/header and trying to load it? or would it be better to just bubble all of them up? – Erich Mirabal Apr 21 '09 at 14:50
  • Surely the naming can be improved and should be adjusted to your actual use case. In this simple example I simply chose to add the specific way used as a suffix. In the end I probably would just use `IsJpeg` or some of your suggestions. Since it is a simple example I didn't want to overload it with exception handling, but typically I would handle exceptions related to file io and access permissions higher up in the stack. – Dirk Vollmar Apr 21 '09 at 15:03
  • 2
    In function HasJpegHeader above, I agree with the FF D8, but it's not always FF E0. Sometimes it's FF E1. So, the function above resulted in FALSE for a correct JPG file. – Ruturaaj Nov 15 '11 at 18:30
  • 1
    I originally had used the HasJpegHeader method. However a more robust variant check (EXIF files have a different marker) can be found in @Orwellophile answer below. – Jordan Jan 29 '15 at 18:03
27

Open the file as a stream and look for the magic number for JPEG.

JPEG image files begin with FF D8 and end with FF D9. JPEG/JFIF files contain the ASCII code for 'JFIF' (4A 46 49 46) as a null terminated string. JPEG/Exif files contain the ASCII code for 'Exif' (45 78 69 66) also as a null terminated string

Simon Gibbs
  • 4,737
  • 6
  • 50
  • 80
  • This is of course not at all a reliable check, since it is trivial to create a non-jpeg file which fulfills these conditions. – jarnbjo Mar 15 '13 at 14:02
  • I reckon it's proportionate to the bulk of use-cases. Sure there are potential security/DoS issues with accepting a non-JPEG, but that's another question I think ;-) – Simon Gibbs Mar 15 '13 at 17:51
  • Most JPEG/Exif files also contain the JFIF code and a few JPEG files contain neither Exif nor JFIF. – hippietrail Jul 08 '23 at 12:01
27

OMG, So many of these code examples are wrong, wrong wrong.

EXIF files have a marker of 0xff*e1*, JFIF files have a marker of 0xff*e0*. So all code that relies on 0xffe0 to detect a JPEG file will miss all EXIF files.

Here's a version that will detect both, and can easily be altered to return only for JFIF or only for EXIF. (Useful when trying to recover your iPhone pictures, for example).

    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;
        }
    }
Orwellophile
  • 13,235
  • 3
  • 69
  • 45
  • Wikipedia shows that the hex for JPEG/JFIF is `4A 46 49 46`, but you're checking for `0x4649464a`. EXIF is `45 78 69 66`, but you're checking for `0x66697845`. I assume your code is correct, but why are they backwards? – vaindil Oct 25 '16 at 15:55
  • 3
    @vaindil I was so totally about to troll you, but then I realised you'd actually gone to Wikipedia and done your own research, and noticed not just that the numbers were different, but that they were actually backwards. So I will answer your question. The answer is [Endianness](https://en.wikipedia.org/wiki/Endianness). If you don't want to read another wikipedia article, the TL;DR version is: **Intel machines stores values in memory ass-backwards**. – Orwellophile Oct 25 '16 at 20:29
  • @Orwellophile Oh wow, I didn't even think about endianness. -_- I know of that, for whatever reason it didn't even cross my mind. Thank you, I appreciate it! – vaindil Oct 27 '16 at 20:25
  • What if wanted to extend this to also check for valid PNG files? – user1932634 May 05 '18 at 18:28
  • 1
    @user1932634 Then you would find out what the first bytes of a PNG file are and add that to the code. – Andrew Morton Sep 06 '18 at 15:41
13

You could try loading the file into an Image and then check the format

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

Alternatively you could open the file and check the header to get the type

Dirk Vollmar
  • 172,527
  • 53
  • 255
  • 316
Lee
  • 1,125
  • 6
  • 7
  • 1
    For each positive case, you'd have decoded the whole image when you might not want to, and for each negative case I expect you'd need to handle an exception - driving the poor guy debugging your code mental hammering on F5. I guess it depends on the scenario but there are other answers that don't have these issues. – Simon Gibbs Apr 21 '09 at 13:17
  • The comparison actually fails. You need to call `ImageFormat.Equals` instead of using the `==` operator. – Dirk Vollmar Apr 21 '09 at 14:40
3

You could find documentation on the jpeg file format, specifically the header information. Then try to read this information from the file and compare it to the expected jpeg header bytes.

Brian Ensink
  • 11,092
  • 3
  • 50
  • 63
3

Read the header bytes. This article contains info on several common image formats, including JPEG:

Using Image File Headers To Verify Image Format

JPEG Header Information

Mitch Wheat
  • 295,962
  • 43
  • 465
  • 541
1

This will loop through each file in the current directory and will output if any found files with JPG or JPEG extension are Jpeg images.

      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");
                }
            }
        }
Armbrat
  • 2,295
  • 1
  • 23
  • 32
1

Depending on the context in which you're looking at this file, you need to remember that you can't open the file until the user tells you to open it.

(The link is to a Raymond Chen blog entry.)

David Webb
  • 190,537
  • 57
  • 313
  • 299
0

Just take the media type of file and verify:

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");
        }
mns
  • 141
  • 6
0

after check extention of file read first four byte of image and two last byte of image like this, do it for two last byte for value 255 , 217 for other file can do it 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
}
Community
  • 1
  • 1
hmfarimani
  • 531
  • 1
  • 8
  • 13
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
user3387978
  • 135
  • 4
0

The code here:

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

Shows you how to get the Meta Data. I guess that would throw an exception if your image wasn't a valid JPEG.

Program.X
  • 7,250
  • 12
  • 49
  • 83
  • Your answer is a classic example of why _only_ links should not be given as answer. The page is now gone and answer is useless now. If you can improvise your answer, it'd be great or else this should be deleted or flagged for deletion. – Mrchief Jul 13 '13 at 22:25
  • It's a fine line between taking others' content and allowing sufficient credit/visits to original material. I chose to credit the source. The problem here is the referenced user not providing a redirect to the new location or even a "Gone". – Program.X Aug 05 '13 at 08:58
  • Yep, agree partly with you there. Crediting the source is required and you have done that by including the link. Unfortunately, SO is not a place for _just_ crediting others - it is meant to provide answers and that is precisely what is lacking here. Accepted answer and @simongibbs' answer is a good example of how to do both and there plenty others in SO that you could use as a reference. Like you said, because 404's are harsh reality and you cannot expect everyone to return a 302, including a gist is helpful and much needed. – Mrchief Aug 05 '13 at 15:29
0

Once you have the extension you could use a regular expression to validate it.

^.*\.(jpg|JPG)$
Shaun Humphries
  • 1,070
  • 9
  • 15
  • 6
    Should include `jpeg` in there as well, and probably spend a minute searching for other less common jpeg file extensions. – Brian Ensink Apr 21 '09 at 12:54
0

Checking the file extension is not enough as the filename might be lying.

A quick and dirty way is to try and load the image using the Image class and catching any exceptions:

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

This isn't ideal as you could get any kind of exception, such as OutOfMemoryException, FileNotFoundException, etc. etc.

The most thorough way is to treat the file as binary and ensure the header matches the JPG format. I'm sure it's described somewhere.

Steve Dunn
  • 21,044
  • 11
  • 62
  • 87
0

The best way would to try and create an image from it using the Drawing.Bitmap (string) constructor and see if it fails to do so or throws an exception. The problem with some of the answers are this: firstly, the extension is purely arbitrary, it could be jpg, jpeg, jpe, bob, tim, whatever. Secondly, just using the header isn't enough to be 100% sure. It can definitely determine that a file isn't a jpeg but can't guarantee that a file is a jpeg, an arbitrary binary file could have the same byte sequence at the start.

Skizz
  • 69,698
  • 10
  • 71
  • 108
-1

You can use the Path.GetExtension Method.

Galwegian
  • 41,475
  • 16
  • 112
  • 158