My Foray into Something Groovy
July 9th, 2009 Krister Schwertfuehrer, Consultant
As is often the beginning of most anything we do, this story starts with necessity! Unfortunately for me, the necessity was caused by my own screw-up: I had to restore my wife’s computer from a backup and instead of giving files their original modified timestamp, I accidentally chose to set the timestamp to the current time! Well, now she lets me know how difficult it is to arrange our digital pictures into their appropriate months when the files are misdated!
So, after a couple months of procrastination and trying out different tools that did not quite do what I expected, I just decided to do it myself. I created a simple program that will correctly date my digital pictures with the date they were taken (I knew enough about the files to know that I should be able to get the date the picture was taken from its metadata). As always, before beginning such an undertaking, make sure you’ve got a backup of anything important; I’d hate to have to tell my wife that I ruined the pictures instead of re-dating them!
Anyway, after listening to my friends talk about Groovy, I thought I’d try out the Pragmatic Programmer philosophy and start to learn a new language this year, Groovy. I’m sure lots of people know a lot about Groovy, but I certainly didn’t know too much. I also didn’t know anything about Exchangable image file format (Exif): http://en.wikipedia.org/wiki/Exchangeable_image_file_format.
For my development during this experiment, I am using IntelliJ IDEA 8.1.3; IntelliJ was free for me from NFJS and it comes with a Groovy Plugin, but Groovy must be installed before it can be used. NOTE: IntelliJ is a really nice IDE, but it is hard to compete with the various other free IDEs out there. I had to find a reason to use it here, as I’ve been interested in finding out how good it really is.
So, download and install Groovy: http://groovy.codehaus.org/Download (I chose the 1.6.3 Windows-Installer and followed all of the defaults). Also, for this “project” I decided to use Drew Noakes’s EXIF Metadata Extraction library after a few searches on Google: http://www.drewnoakes.com/code/exif/ -> metadata-extractor-2.3.1.jar
Not knowing anything about EXIF or Groovy, I started small, using a Groovy script to try and see all of the information available on a JPEG, in a very Java-like way (I removed comments to keep it somewhat shorter):
import com.drew.metadata.Metadata
import com.drew.imaging.jpeg.JpegMetadataReader
import com.drew.metadata.Directory
import com.drew.metadata.Tag
String picDirectory = "C:/Temp/Test Pics";
File jpegFile = new File(picDirectory + "/Canon EOS 20D (1).jpg");
Metadata metadata = JpegMetadataReader.readMetadata(jpegFile);
Iterator directories = metadata.getDirectoryIterator();
while (directories.hasNext()) {
Directory directory = (Directory) directories.next();
Iterator tags = directory.getTagIterator();
while (tags.hasNext()) {
Tag tag = (Tag) tags.next();
System.out.println(tag);
}
}
... [Exif] Make - Canon [Exif] Model - Canon EOS 20D ... [Exif] Date/Time - 2004:09:19 12:25:20 ... [Exif] Exposure Time - 1/250 sec [Exif] F-Number - F9 [Exif] Exposure Program - Program normal [Exif] ISO Speed Ratings - 200 [Exif] Exif Version - 2.21 [Exif] Date/Time Original - 2004:09:19 12:25:20 [Exif] Date/Time Digitized - 2004:09:19 12:25:20 ...
as well as about a hundred other items! Wow, that’s a lot of info and I thought it was a good start. However, this gives me too much information. I just want the date/time the picture was taken. So, back to the drawing board.
I went back to the JavaDocs and samples for Metadata Extractor at http://www.drewnoakes.com/code/exif/ and http://www.drewnoakes.com/code/exif/javadoc/ to find that I can get date information directly from ExifDirectory using the getDate() method and the Constants ExifDirectory.TAG_DATETIME, ExifDirectory.TAG_DATETIME_ORIGINAL and ExifDirectory.TAG_DATETIME_DIGITIZED:
import com.drew.metadata.Metadata
import com.drew.imaging.jpeg.JpegMetadataReader
import com.drew.metadata.Directory
import com.drew.metadata.Tag
import com.drew.metadata.exif.ExifDescriptor
import com.drew.metadata.exif.ExifDirectory
String picDirectory = "C:/Temp/Test Pics";
File jpegFile = new File(picDirectory + "/Canon EOS 20D (1).jpg");
Metadata metadata = JpegMetadataReader.readMetadata(jpegFile);
Directory exifDirectory = metadata.getDirectory(ExifDirectory.class);
Date picDate1 = exifDirectory.getDate(ExifDirectory.TAG_DATETIME);
Date originalDate = exifDirectory.getDate(ExifDirectory.TAG_DATETIME_ORIGINAL);
Date picDate3 = exifDirectory.getDate(ExifDirectory.TAG_DATETIME_DIGITIZED);
System.out.println("picDate1: " + picDate1);
System.out.println("originalDate: " + originalDate);
System.out.println("picDate3: " + picDate3);
which resulted in this:
picDate1: Sun Sep 19 12:25:20 EDT 2004 originalDate: Sun Sep 19 12:25:20 EDT 2004 picDate3: Sun Sep 19 12:25:20 EDT 2004
Bingo, now if I could figure out the difference between those three dates…
A review of the EXIF standard (http://www.w3.org/2003/12/exif/) shows that TAG_DATETIME_ORIGINAL and TAG_DATETIME_DIGITIZED should be the same for my camera. So, I’m going to choose the TAG_DATETIME_ORIGINAL for my basis date.
Now I have to set the file modified date. A review of the File object shows that I can call the lastModified() method to get the last modified date, and I can call setLastModified() to set the last modified date:
import com.drew.metadata.Metadata
import com.drew.imaging.jpeg.JpegMetadataReader
import com.drew.metadata.Directory
import com.drew.metadata.Tag
import com.drew.metadata.exif.ExifDescriptor
import com.drew.metadata.exif.ExifDirectory
String picDirectory = "C:/Temp/Test Pics";
File jpegFile = new File(picDirectory + "/Canon EOS D60.jpg");
Metadata metadata = JpegMetadataReader.readMetadata(jpegFile);
Directory exifDirectory = metadata.getDirectory(ExifDirectory.class);
Date originalDate = exifDirectory.getDate(ExifDirectory.TAG_DATETIME_ORIGINAL);
System.out.println("originalDate: " + originalDate);
Date lastModified = new Date(jpegFile.lastModified());
System.out.println("Last modified time of file is : " + lastModified );
boolean timeUpdated = jpegFile.setLastModified(originalDate.getTime());
System.out.println("Was last modified time set successfully? " + timeUpdated);
System.out.println("File last modification date is : " + new Date(jpegFile.lastModified()));
which resulted in this:
originalDate: Sat Oct 26 19:26:35 EDT 2002 Last modified time of file is : Tue Jun 23 23:40:47 EDT 2009 Was last modified time set successfully? true File last modification date is : Sat Oct 26 19:26:35 EDT 2002
Now, all that remains is iterating through all my pictures and setting the modified time/date on all JPG files. This is where I learned a little bit more about Groovy. Methods can be included right inside the script and looping is so easy!
import java.io.File
import com.drew.metadata.Metadata
import com.drew.imaging.jpeg.JpegMetadataReader
import com.drew.metadata.Directory
import com.drew.metadata.Tag
import com.drew.metadata.exif.ExifDescriptor
import com.drew.metadata.exif.ExifDirectory
String picDirectory = "C:/Temp/Test Pics";
File dir = new File(picDirectory);
ArrayList files = getFiles(dir);
files.each {
println it;
File jpegFile = it;
Metadata metadata = JpegMetadataReader.readMetadata(jpegFile);
Directory exifDirectory = metadata.getDirectory(ExifDirectory.class);
Date originalDate = exifDirectory.getDate(ExifDirectory.TAG_DATETIME_ORIGINAL);
System.out.println("originalDate: " + originalDate);
Date lastModified = new Date(jpegFile.lastModified());
System.out.println("Last modified time of file is : " + lastModified );
boolean timeUpdated = jpegFile.setLastModified(originalDate.getTime());
System.out.println("Was last modified time set successfully ?:" + timeUpdated);
System.out.println("File last modification date is : " + new Date(jpegFile.lastModified()));
}
ArrayList<File> getFiles(File dir) {
ArrayList files = new ArrayList();
if(dir.isDirectory()) {
dir.listFiles().each{
File file = it;
if(file.isDirectory()) {
files.addAll(getFiles(it));
} else {
files.add(it);
}
}
} else {
files.add(dir);
}
return files;
}
Voila! My test files all have their correct dates again! Of course, to make this a bit more complete, it would be nice to have some error checking and some logging (particularly when the file does not get a new date), but I’ll leave that for another time… after a couple more months of procrastination
Entry Filed under: Software Development






Leave a Comment
Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
Trackback this post | Subscribe to the comments via RSS Feed