You Can Have It In Any Color – As Long As It’s Black

You Can Have It In Any Color – As Long As It’s Black

I’ve been banging my head up against a wall today over something that should be easy.

What was I trying to do?

Well, I’ve been working this week on a new app for that will allow you to post photos from your iPhone to the TweetPhoto web service.  In fact I wrote about it here.

I thought I had one problem licked – sending geo tag information to the API call.  As it turns out, I had only HALF the problem licked.

Initially, I was using the phone’s CoreLocation services to determine location and upload that to the API.  This is totally cool when you are using the camera.

Not so much when uploading photos taken elsewhere.  Ouch.

OK.  No problem.  I know the phone stores EXIF (exchangeable image file format) information with the JPEGS it takes, so it should be a slam dunk to grab that from th image picker control, right?

Wrong, grasshopper (with props to the recently deceased David Carradine).

The image picker STRIPS all EXIF information from photos passed in from the camera roll, so you, Mr. and / or Mrs. Developer, are screwed.

OK.  I’m a fart smeller.  I should be able to figure this out.

Hey – what if I can find where the camera roll is on the iPhone, enumerate it directly and read the image files from there?

Oh.  Heavenly Days.  That is a GREAT idea.

So, I trot out this gem, feeling like I have the problem close to being solved:

-(void)getCoords:(UIImage *)image lat:(float*)latAddr lon:(float*)lonAddr {

NSDirectoryEnumerator *enumerator  = [[NSFileManager defaultManager] enumeratorAtPath:  @”var/mobile/Media/DCIM/100APPLE”];
NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];
id curObject;

*latAddr = 0;
*lonAddr = 0;

while ((curObject = [enumerator nextObject])) {
if ([[curObject pathExtension] isEqualToString:@”JPG”]) {

NSData * fileContents = [NSData dataWithContentsOfFile:[NSString stringWithFormat:@”var/mobile/Media/DCIM/100APPLE/%@”, curObject]];
UIImageView * seeMe = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
seeMe.image = [UIImage imageWithData:fileContents];

// First, we’ll get a JPEG representation of the image
EXFJpeg* jpegScanner = [[EXFJpeg alloc] init];
[jpegScanner scanImageData:fileContents];
EXFGPSLoc * lat    = [jpegScanner.exifMetaData tagValue:[NSNumber numberWithInt:EXIF_GPSLatitude]];
NSString * latRef = [jpegScanner.exifMetaData tagValue:[NSNumber numberWithInt:EXIF_GPSLatitudeRef]];
EXFGPSLoc * lon    = [jpegScanner.exifMetaData tagValue:[NSNumber numberWithInt:EXIF_GPSLongitude]];
NSString * lonRef = [jpegScanner.exifMetaData tagValue:[NSNumber numberWithInt:EXIF_GPSLongitudeRef]];

float flat = [[NSString stringWithFormat:@”%f”, lat.degrees.numerator + ((float)lat.minutes.numerator / (float)lat.minutes.denominator) / 60.0] floatValue];
float flon = [[NSString stringWithFormat:@”%f”, lon.degrees.numerator + ((float)lon.minutes.numerator / (float)lon.minutes.denominator) / 60.0] floatValue];

if ([[latRef substringToIndex:1] isEqualToString:@”S”]) {
flat = -flat;
if ([[lonRef substringToIndex:1] isEqualToString:@”W”]) {
flon = -flon;

// Does the image match???
if (seeMe == image) {
*latAddr = flat;
*lonAddr = flon;

[jpegScanner release];
[seeMe release];

[innerPool release];
innerPool = [[NSAutoreleasePool alloc] init];
[innerPool release];
innerPool = nil;

NOW I’m rolling.  This works GREAT.  I can read images, extract EXIF information… feeling good.

Until I realize that I have NO way to associate the files that I am reading directly from what the image picker returns to me.  Did I just say “shit” out loud?  Because that is what I’m swimming in.

The image picker simply hands back an UIImage with some editing information.  That’s it.

OK, OK, OK.  Maybe I can compare NSData elements… or UIImage elements against what I read from disk and what the picker sends back… so far, neither of those approaches is working.

And now I’m sitting here, realizing that I can accurately describe ANY image’s geo tagging information.  I just can’t pick a SPECIFIC image from the bunch, well, at least using Apple’s APIs.

I’m coming to the sad realization that I might have to write my own bastardized version of the image picker, at least for scrolling through the camera roll.

I ain’t skeered to do it.  I just wish I didn’t have to.

But that looks like that’s exactly what I’m gonna have to do.  Damn it.

5 thoughts on “You Can Have It In Any Color – As Long As It’s Black

  1. “OK, OK, OK. Maybe I can compare NSData elements… or UIImage elements against what I read from disk and what the picker sends back… so far, neither of those approaches is working.”

    Note that if the image is a saved image (from safari) it might reside as jpg or other on disk, but when you get it in hand as NSData from UIImage, it’s already png…


  2. Hi David,
    I am just starting out on building iphone apps and I need to build an app which extracts, displays and removes EXIF from previous saved photos. During my course of looking all over the web for a solution, since the UIImagePicker removes all exif, I finally landed on your blog.

    So, as it seems from your other blog post, you have implemented your own version of the imagepicker in the tweetphoto app. I tried looking at the source, but couldn’t figure out how it’s extracting the exif from the images (since I found no calls to the exif library, as described in this post) or how its reading the images (since I can’t find any instances of DCIM in the code).I guess you’re just using the imagepicker in a different way.

    I’m still a n00b at this, and I’ll highly appreciate it, if you could shed some light on the working of the tweetphoto app.

    Also keep your highly informative blog posts coming, I have learnt a lot in the last few days of reading them.

    Thanks & Regards,


    1. Joe in the current incarnation of the TweetPhoto app we simply use the iPhone UIImagePicker. In the first release of the app, I used a third party library for reading and writing EXIF data. That is no longer the case in the existing app, where I assumed you are perusing the source.

      Thanks for the kind words.

      – D


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s