I was trying to organize photos of my cats on my hard drive today, they all sit in this one folder called "Cats", unsorted and with no hierarchy. Since I wanted to keep track of my cats' growth progress and sort photos according to the different periods, logically, I decided to place them into different subfolders according to which year and month they were taken. Sounds like an excellent solution, doesn't it?
- Look at photo
- Check the Date Taken field of the photo
- Create folder with the photo's taken year and month in format "YYYY.MM"
- Move the photo into the corresponding folder
- Repeat all steps above for the next photo
Here's what I did manually for about 20-30 photos... until I realized I have over 2000 photos waiting for me to go through. So I was thinking, there must be a better and faster way to do this. In other words, guess it's time for the nerdy side of me to kick in ;)
The Better Solution
Yes, let's build an app to automate it! I went with .NET 4 since I just installed it along with Visual Studio 2010 a few days ago (and I love to try new things out!) and built a simple interface using XAML in WPF:
It's very quick and easy to build an interface like this using XAML in WPF, especially if you're familiar with XML. For the interface I have above, I simply started off by defining the grid columns and grid rows using Grid.RowDefinitions and Grid.ColumnDefinitions and continued by placing the UI components into the grid. In particular, I defined 4 rows and 2 columns for the interface above:
- TextBlock on Row 0, Column 1 for program description (Note: Grid rows/columns in WPF begins with 0)
- "Directory" Label on Row 1, Column 0
- TextBox for retrieving target directory on Row 1, Column 1
- Two buttons - Categorize and Reset - on Row 2, Column 1
- Copyright TextBlock on Row 3, Column 1
For example, to place the label "Directory" on Row 1, Column 0 of the grid, all you need is to specify the Grid.Row and Grid.Column position in the XAML for the label:
<Label Grid.Row="1" Grid.Column="0" x:Name="labelDir" VerticalAlignment="Center" Padding="2" Margin="2">Directory: </Label>
- Here's a brief introduction to the WPF Grid Control blogged by Brian Mains: http://dotnetslackers.com/Community/blogs/bmains/archive/2007/07/27/Introduction-to-the-WPF-Grid-Control.aspx
- More details on MSDN: http://msdn.microsoft.com/en-us/library/bb613551.aspx
After creating the interface, I proceeded with the backend work. The basic logic of the program is very similar to the manual solution we listed above, i.e. loop through all the photos in the target directory, check their Date Taken value from the metadata, and place them in their corresponding directory (create one if one does not exist). Now the harder question is, how do we read the metadata and retrieve the Date Taken value using C# in .NET 4?
Fortunately, since .NET 3, we've been able to retrieve metadata from basic photos using System.Windows.Media.Imaging.BitmapSource via image piping. For WPF, supported formats include BMP, GIF, JPEG, PNG, and TIFF images. Once we have created the BitmapSource object for our image, the BitmapSource.Metadata property can return all metadata associated with the image. Therefore, we'd be able to retrieve the Date Taken value of the photo as required:
- Here's an excellent blog post written by Bret Patterson about how to retrieve image metadata in .NET 3 (also works for .NET 4) with a working code example: http://blog.bretpatterson.com/post/2007/12/06/Working-with-Image-Metadata-in-NET-30-Part-I.aspx
Finally, we just need to parse in the Date Taken String (it's returned as a String from the BitmapSource.Metadata property), create a directory if needed, and move the file to their corresponding subfolder. These steps could be achieved using System.IO.Directory and System.IO.File.
The program was able to go through all supported format photos from a specified directory and move the ones with an existing Date Taken value into their corresponding folder (in "YYYY.MM" format for the ease of sorting)! In particular, the program automatically went through over 2000 of my cat photos and moved all 1265 valid photos into the correct subfolders (took approximately 5 minutes with no special optimization). What's better is that I can now re-use this tool for similar scenarios in the future!
Successfully moved 1265 photos to their corresponding subfolders.
Successfully moved 1265 photos to their corresponding subfolders.Subfolders are created in the target directory when needed.
Photos are moved into their corresponding subfolders. These photos are taken in June, 2006.
...and this is one reason why I love technology and why I like to code for fun! I hope this post helped those of you who are interested in creating tools alike. If you're interested in getting a copy of the tool, feel free to contact me in the comments or email me at firstname.lastname@example.org.
For those of you who are NOT geeky...
If you use Windows Live Photo Gallery and have included your photos in the library, you can easily sort or filter the photos by Date Taken with just a few clicks: In the navigation pane, under Date taken, click a year to see all of the photos and videos taken during that year, and then select a month or date if required.
Happy coding! Meow!