Tuesday, September 3, 2013

C# - Read Exif metadata for Date Taken

I am in the process of writing a C# utility to move my photo collection to various locations based on either the date taken, date created or date modified.  Originally, I used the Image.FromFile method, then GetPropertyItem to pull DateTakenValue property.  While this did work, it was terribly inefficient, especially when dealing with thousands of files.  Alternatively, the method below is many times faster and significantly more efficient.

For example, a 757kb jpg file using Image.FromFile took 67ms to get the date taken property.  Using the method below, this was reduced to 4ms.

Remember to add a reference to both PresentationCore and WindowsBase.

 using System.Windows;  
 using System.Windows.Media.Imaging;
  
 private DateTime getDateTaken(string inFullPath)  
     {  
       DateTime returnDateTime = DateTime.MinValue;  
       try  
       {  
         FileStream picStream = new FileStream(inFullPath, FileMode.Open, FileAccess.Read, FileShare.Read);  
         BitmapSource bitSource = BitmapFrame.Create(picStream);  
         picStream.Close();   
         BitmapMetadata metaData = (BitmapMetadata)bitSource.Metadata;          
         returnDateTime = DateTime.Parse(metaData.DateTaken);  
       }  
       catch  
       {  
         //do nothing  
       }  
       return returnDateTime;  
     }  

2 comments:

  1. Nice Post Mike!

    What you thought of making two years ago, is what I was thinking now to build. So my search about how to retrieve DateTaken property in C# led me to your article after spending some time on msdn. Because they just have a VB example to set properties to image not how to get them from an existing image.

    When I first tried your example I got nothing, the metaData object returned to me for various jpg files was null. I thought to write you about it but then I thought of making a working solution of it before posting you just the bug.


    I just spend little more time on it about 10-15 mins (Thanks to your code) and came up with a little different solution.


    FileStream picStream = new FileStream(allImageFilesInSource[0].FullName, FileMode.Open, FileAccess.Read, FileShare.Read);
    JpegBitmapDecoder decoder = new JpegBitmapDecoder(picStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None);

    BitmapMetadata metaData = new BitmapMetadata("jpg");
    BitmapFrame frame = BitmapFrame.Create(decoder.Frames[0]);

    metaData = (BitmapMetadata)frame.Metadata;
    txtDateTaken.Text = metaData.DateTaken;
    picStream.Close();

    While debugging I found that Metadata property had the DateTaken value but when not in debug mode I found it again returned me null. Little debugging more I got that the MetaData is only available until picStream is open, the moment you close it you lose it.

    Then I tried back your code and just put the picStream.Close() at the end and found your code is working too!!!

    I wonder how you are just able to get this property after closing the Stream!!

    all together thanks for that code, I can just start writing my version of Photos Organiser based on DateTaken from now. and I hope you have had created that by now. :)

    ReplyDelete
  2. So glad to hear this helped you Sidhant!

    ReplyDelete