Thursday, December 11, 2008

Camera Focal Range Data application

I'm currently using a point & shoot camera (Canon S2 IS), but have a DSLR on the way (Canon Rebel XS). The DSLR comes with a kit lens that ranges from 18-55mm (28.8mm - 88mm in 35mm equivalents), which is quite a bit shorter than my p&s (up to 432mm equiv!). So I got worried that I wouldn't be too happy with just the kit lens. At the same time, I wanted to try out LINQ in .NET, so a quick project was born...

I wrote a bare-bones console application that reads in EXIF data from images, extracts the focal length of each, and uses some simple LINQ queries that lets me see exactly how many photos were taken in wide, normal, tele, and super tele modes. It recurses through directories from a starting directory you specify, and tries to get info on all JPEG images.



Right now, there's no nice GUI, it's not multi-threaded, you can only search one folder at a time, there is no progress bar, and you can't actually see what images fall into which category, but if there's any interest in this app at all, I'll add all that sometime soon.

Also, you have to enter a 35mm focal length equivalent for the categories to be accurate. This is annoying, because for point and shoots, that info is sometimes hard to find. I had to actually take a picture all the way zoomed in, and compare the specs on dpreview.com with the EXIF data (72mm max zoom in the EXIF = 432mm max zoom in the specs, so it has a multiplier of "6"). I may end up looking up the multipliers on a bunch of popular cameras and just ask the user to select his/her camera, or optionally manually enter the focal length multiplier if the user's camera is not on the list.

Anyway, the application is fully working in it's current state - all you need is the .NET 3.5 framework. If you want to use the app and can't figure out the proper multiplier to use, just post a comment here, and I or another reader can certainly help you out.

No crazy code in this app, but here's the LINQ part:

//generic list
private List<double> zoomData;
...
zoomData = new List<double>();
...
//code in the directory/file loop
zoomData.Add(focalLength * focalLengthX);
...
int shortTele = (from t in zoomData where t > 100 && t <= 150 select t).Count();

In my case, I was happy to see that I had a significant amount more wide and normal shots than telephoto shots, so maybe I won't need an extra lens after all.

You can download the app here.

UPDATE: Picasa somehow figures out the 35mm equiv. from the EXIF data. I'm going to figure out how they're doing it and update my application soon.

Wednesday, December 3, 2008

System.Net.Mail throws "no such user" exceptions w/ Lotus Domino!

Code that I had running for years without issues suddenly broke with the error "Mailbox unavailable. The server response was: user@domain.com... No such user". Very useful, as with this information, I can now automate (or at least partially automate) internal mailing list management.

For now, I've just added code to catch this specific exception (in addition to the catch-all SmtpException) to have it generate a work order ticket if there's a problem:

try {
smtp.Send(newsletter);
} catch(System.Net.Mail.SmtpFailedRecipientException ex) {
//generate work order...
}

There's also "SmtpFailedRecipientsException" which triggers only if it can't send an email to all the recipients, though I don't see why you would use this over SmtpFailedRecipientException, as the latter informs you in the exception message if all recipients haven't received the email in addition to handling the case where one or some recipients failed.

However, I've noticed that if more than one recipient email fails, it only displays the first email address that failed in the error message. Makes sense, since it probably is processing one email completely at a time, and if it fails on one, it doesn't go any further. The solution to this, I guess, would be to have each email sent out within a loop of separate SMTP calls instead of using the handy "mail.To.Add" method. There would most likely be a performance hit doing it this way, though.

I'm going to keep looking into it, but does anyone know of a better way?

Also, I assume this works with MS Exchange as well, but don't know anyone using email with Exchange to test with. I have verified it doesn't work with Gmail and Hotmail, so this is best used only with an environment where you know that everyone is on the same mail server.