Batch to Get Photo Metadata Timestamp

CycloWizard

Lifer
Sep 10, 2001
12,348
1
81
I'm trying to write a quick program which looks at all of the jpeg files in a folder and records the timestamp (DateTime property) from lots of photos in a text file. I originally wrote it in MATLAB, but it will be used elsewhere and we are having lots of issues with language and version conflicts. Rather than trying to sort through all of these problems across time zones, and since transferring a TB of photos across the interwebs isn't an appealing option, does anyone know of a quick script/batch file/program that can do this? I saw plenty that write a timestamp to the photo itself, but I need the photos intact and I need the timestamp in text format for later analysis. Any help is appreciated.
 

CycloWizard

Lifer
Sep 10, 2001
12,348
1
81
Thanks. That says it will access file system information about when the file is created/changed, but I need the metadata from the actual photo regarding when it's taken. The old version of MATLAB only gives access to the former, while the newer version that I have allows access to both, and this appears to be where the problem arises. I'll see if I can use something like that API to access it because at least I know the information is there.

edit: I found this by searching the MSDN for exif metadata. I'll see if I can get that to work.
 
Last edited:

CycloWizard

Lifer
Sep 10, 2001
12,348
1
81
That's what you need. It's like reading the id3 tag info from an mp3 file.
Right. Cogman pointed me in the right direction. My non-MATLAB programming is a bit rusty, so hopefully that's all I need. I'll post back if I can get something working.
 

Cogman

Lifer
Sep 19, 2000
10,284
138
106
Right. Cogman pointed me in the right direction. My non-MATLAB programming is a bit rusty, so hopefully that's all I need. I'll post back if I can get something working.

:) that is whats so great about the msdn. Glad my incorrect solution lead to a correct one.
 

CycloWizard

Lifer
Sep 10, 2001
12,348
1
81
:) that is whats so great about the msdn. Glad my incorrect solution lead to a correct one.
Yep. I'm sure this is ugly as hell for people who are used to programming in C/C#, but here we go. The precision on this timestamp isn't great (1 second), but that's what we have so it will have to do.
Code:
private void button1_Click(object sender, EventArgs e)
{
    pathBrowser.ShowDialog();
    DirectoryInfo di = new DirectoryInfo(pathBrowser.SelectedPath);

    FileInfo[] rgFiles = di.GetFiles("*.jpg");
    foreach (FileInfo fi in rgFiles)
    {
        //Combine full path\file
        string fname = di.ToString() + "\\" + fi.Name;
                

        //Read in image
        Image i = Image.FromFile(fname);
                
        //Get date/time photo was taken
        DateTime dt = GetDateTaken(i);

        //string dt1 = dt.ToLongTimeString();//full time string
        string dt2 = dt1.Substring(0, dt1.Length - 3);//time without AM/PM

        int ind1 = dt2.IndexOf(":",0);//find first colon
        int ind2 = dt2.IndexOf(":", ind1+1);//find second colon

        //Convert strings to integers                
        string hh = dt2.Substring(0, ind1);
        string mm = dt2.Substring(ind1+1, ind2-ind1-1);
        string ss = dt2.Substring(ind2 + 1, 2);

        Int32 hours = Convert.ToInt32(hh);
        Int32 minutes = Convert.ToInt32(mm);
        Int32 seconds = Convert.ToInt32(ss);

        //Account for AM/PM
        int ind=0;
        if (AMPM != "AM")
            ind=ind+12;

        //Calculate total seconds since midnight
        Int32 TotalTime = 3600 * (hours+ind) + 60 * minutes + seconds;
    }
}

public DateTime GetDateTaken(Image targetImg)
{
    //Property Item 36867 corresponds to the Date Taken
    PropertyItem propItem = targetImg.GetPropertyItem(36867);
    DateTime dtaken;

    //Convert date taken metadata to a DateTime object
    string sdate = Encoding.UTF8.GetString(propItem.Value).Trim();
    string secondhalf = sdate.Substring(sdate.IndexOf(" "), (sdate.Length - sdate.IndexOf(" ")));
    string firsthalf = sdate.Substring(0, 10);
    firsthalf = firsthalf.Replace(":", "-");
    sdate = firsthalf + secondhalf;
    dtaken = DateTime.Parse(sdate);
    return dtaken;
}
 

Crusty

Lifer
Sep 30, 2001
12,684
2
81
That looks like C# to me? If so, check out the DateTime API http://msdn.microsoft.com/en-us/library/system.datetime.aspx

It exposes Properties that let you get the Hour/Minute/Seconds as integers so you don't have to go through manually parsing strings. It's 24-based too so you don't even have to accounts for AM/PM. If you're going any sort of large scale recording you should see a pretty good speedup.
 

CycloWizard

Lifer
Sep 10, 2001
12,348
1
81
That looks like C# to me? If so, check out the DateTime API http://msdn.microsoft.com/en-us/library/system.datetime.aspx

It exposes Properties that let you get the Hour/Minute/Seconds as integers so you don't have to go through manually parsing strings. It's 24-based too so you don't even have to accounts for AM/PM. If you're going any sort of large scale recording you should see a pretty good speedup.
Thanks! I can replace that whole parsing/calculation mess with
Code:
Int32 TotalTime = 3600 * dt.Hour + 60 * dt.Minute + dt.Second;
The whole thing (save the metadata parser included in the previous post) is now just
Code:
private void button1_Click(object sender, EventArgs e)
{
    lblText.Text = "Running.";
    pathBrowser.ShowDialog();
    DirectoryInfo di = new DirectoryInfo(pathBrowser.SelectedPath);
    TextWriter tw = new StreamWriter(di + @"\Results.txt");// create a writer and open the file           
    FileInfo[] rgFiles = di.GetFiles("*.jpg");//all jpeg fiels in folder
    foreach (FileInfo fi in rgFiles)
    {
        string fname = di.ToString() + "\\" + fi.Name;//Combine full path\file
        Image i = Image.FromFile(fname);//Read in image
        DateTime dt = GetDateTaken(i);//Get date/time photo was taken
        Int32 TotalTime = 3600 * dt.Hour + 60 * dt.Minute + dt.Second;//number of seconds since midnight
        tw.WriteLine(TotalTime.ToString());// write a line of text to the file
    }
    tw.Close();// close the stream
    lblText.Text = "Finished processing " + di.ToString() + ".";
}

edit: Now, can anyone tell me how to compile this? I found some online tutorials for console applications with a single file, but I can't seem to find anything for form-based applications with multiple files. All I could find were some ideas about using "msbuild MyFile.csproj" from the command line, but that is giving me all kinds of errors:
C:\Users\Matt Work\Documents\Visual Studio 2010\Projects\JPEGTimestampReader\JPEGTimestampReader>compile.bat

C:\Users\Matt Work\Documents\Visual Studio 2010\Projects\JPEGTimestampReader\JPEGTimestampReader>c:\windows\microsoft.net\framework\v4.0.30319\msbuild.exe /property:WarningLevel=2;OutputDir=Compiled JPEGTimestampReader.csproj

Microsoft (R) Build Engine Version 4.0.30319.1
[Microsoft .NET Framework, Version 4.0.30319.1]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 3/9/2011 8:32:24 PM.
Project "C:\Users\Matt Work\Documents\Visual Studio 2010\Projects\JPEGTimestampReader\JPEGTimestampReader\JPEGTimestampReader.csproj" on node 1 (default targe
ts).
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(483,9):
error : The OutputPath property is not set for project 'JPEGTimestampReader.csproj'. Please check to make sure that you have specified a valid combination of
Configuration and Platform for this project. Configuration='Debug' Platform='MCD'. You may be seeing this message because you are trying to build a projec
t without a solution file, and have specified a non-default Configuration or Platform that doesn't exist for this project. [C:\Users\Matt Work\Documents\Visua
l Studio 2010\Projects\JPEGTimestampReader\JPEGTimestampReader\JPEGTimestampRea3der.csproj]
Done Building Project "C:\Users\Matt Work\Documents\Visual Studio 2010\Projects\JPEGTimestampReader\JPEGTimestampReader\JPEGTimestampReader.csproj" (default targets) -- FAILED.


Build FAILED.

"C:\Users\Matt Work\Documents\Visual Studio 2010\Projects\JPEGTimestampReader\JPEGTimestampReader\JPEGTimestampReader.csproj" (default target) (1) ->
(_CheckForInvalidConfigurationAndPlatform target) ->
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(483,9) : error : The OutputPath property is not set for project 'JPEGTimestampReader.csproj'. Please check to make sure that you have specified a valid combination of Configuration and Platform for this project. Configuration='Debug' Platform='MCD'. You may be seeing this message because you are trying to build a project without a solution file, and have specified a non-default Configuration or Platform that doesn't exist for this project. [C:\Users\Matt Work\Documents\Visual Studio 2010\Projects\JPEGTimestampReader\JPEGTimestampReader\JPEGTimestampReader.csproj]

0 Warning(s)
1 Error(s)

Time Elapsed 00:00:00.07
I'll post updates as (if?) I make progress. Thanks again for the help everyone. :beer;
 
Last edited:

CycloWizard

Lifer
Sep 10, 2001
12,348
1
81
Apparently VS 2010 Express has a nice built-in compiler that I finally found just using the build -> publish function.
 

Ken g6

Programming Moderator, Elite Member
Moderator
Dec 11, 1999
16,667
4,606
75
If you're still having trouble, I would point you to this program and this blog post. Then all you need is to pipe the output through 'find "Exif:DateTimeOriginal:"' or something like that.
 
Last edited:

CycloWizard

Lifer
Sep 10, 2001
12,348
1
81
If you're still having trouble, I would point you to this program and this blog post. Then all you need is to pipe the output through 'find "Exif:DateTimeOriginal:"' or something like that.
Thanks. I just got all of the results from the guy, so apparently mine compiled fine and worked. I knew there had to be a library out there that would just let me draw out the property I wanted, so next time I'll definitely use this.