I was thinking of an app to build for tech Friday and I remember running in to @willyfoo the other day. He mentioned he needed an application that would read in EXIF data from photographs and rotate them based on the orientation meta tag. It was quite a good exercise cause it allowed me to play around with a few things.
Problem 1: EXIF what?
Although I play around with photography once in a while (I bought a camera last year and I haven’t put any serious effort into it just yet), there are a few concepts which I have yet to understand. So apparently, cameras have a way of storing meta data into the photos you take. Some cameras store what its orientation is when you take a picture. So today, I brought my camera to work and took a few photographs as test photos. I found an existing library on CodeProject that will allow you to read EXIF data from photos called ExifLib.
So now, I can extract the data. The next step was understanding what code means what. http://www.impulseadventure.com/photo/exif-orientation.html gives a graphical explanation for the values of the Orientation metadata.
Problem 2: UI
To be honest, this is something that really needs to be thought through. I am guessing traditional applications would have a UI such as this that will allow you to select a file you want to “fix”. But then I thought, what if I wanted to do a batch job? I guess I could then select a directory. And then I remembered the challenge I had when I dealt with photos when uploading to facebook where my photos aren’t always in the same directory.
I then remembered a tweet by @MSExpression pointing to a blog post by kirupa where he talks about how you can enable drag & drop onto WPF components. So that is settled, Drag & Drop. I built a simple UI with a ListBox where you can drag your files to and an Image component where you can preview the rotated image.
There might be cases when the application messes up the auto orienting and you’d rather do it yourself manually. The UI allows you to select/de-select the files you want to save changes to. I have to say, it’s not the prettiest or most intuitive way to do it but I am not creative so this will have to do.
Problem 3: Preserving EXIF Data
I had originally thought it would be as easy as
1 Bitmap bmPhoto = new Bitmap(filePath);
but I was wrong. First, I realized that although it would successfully rotate the image, it would also bloat up the file (as it was saved without compression) plus, it would lose all the EXIF data the photos had. I don’t think this is something that @willyfoo would have wanted ^_^. So I dug around and found this post that showed you how to resize and manipulate jpegs while preserving the metadata. I did a bit of trimming as the code had stuff to resize the image, which I didn’t want to do for this round. One issue though, is because it encodes the bitmap using some parameters that i can’t figure out just yet (am just lazy too :p) It bloats the file up by a bit.
Problem 4: Saving Changes
Because my UI shows a preview of the image that was rotated, I got some errors where “the file is being used by a process” once I loaded them up into the application and tried to rename/delete them. This post on the msdn forum showed the fix for this.
You can download the code here:
The application is functional but there is definitely a lot of room for improvement 🙂
1. Design – I think this application can be a lot nicer looking if I actually spend time on it. There’s a lot the WPF platform can do to “jazz up” the look and feel of the UI. I think my biggest challenge right now is coming up with a concept that would be cool looking enough :p
2. I’m not sure what happens if I drag&drop none images into the application. This line was supposed to take care of that:
1 if (e.Data.GetDataPresent(DataFormats.Bitmap))
3 ///some code here
But for some reason, files I drag&drop into the app don’t get recognized as a Bitmap. I had to use DataFormats.FileDrop instead.
3. Bloating of image. As I mentioned in problem 3, I’m not very familiar with how encoding works so the app actually bloats the image size quite a bit. I think the following lines take care of the encoding, but when I try to step down on the encParm, it makes the image size smaller than the source. I figured, bigger is better.
1 System.Drawing.Imaging.Encoder enc = System.Drawing.Imaging.Encoder.Quality;
2 System.Drawing.Imaging.EncoderParameters encParms = new EncoderParameters(1);
3 System.Drawing.Imaging.EncoderParameter encParm = new EncoderParameter(enc,100L);
4 encParms.Param = encParm;
5 ImageCodecInfo codecInfo = ImageCodecInfo.GetImageEncoders();
6 ImageCodecInfo codecInfoJpeg = codecInfo;
That’s it for now, until next Tech Friday!