Since I asked the question I have done some more experimentation and think I know the answer now. All results were gotten on iOS 4.2 which is all I care about...
First of all, we were using UIImageJPEGRepresentation
ala:
NSData *imageData = UIImageJPEGRepresentation(self.selectedImage, 0.9);
which seems to not give you (much of) the metadata (EXIF, GPS, etc.) that is in the image. Fair enough and I think that's well-known.
My testing shows that the JPEG in the "default representation" for the image asset will contain all the metadata, including EXIF and GPS information (assuming it's there in the first place). You can get that image by going from the asset URL to the Asset to the asset's default representation (ALAssetRepresentation) and then using the getBytes method/message to retrieve the bytes for the JPEG image. That stream of bytes has the aforementioned metadata in it.
Here's some example code that I use for this. It takes an Asset URL, presumed to be for an image, and returns NSData with with the JPEG. Caveat emptor with respect to your use, error handling in the code, etc.
/*
* Example invocation assuming that info is the dictionary returned by
* didFinishPickingMediaWithInfo (see original SO question where
* UIImagePickerControllerReferenceURL = "assets-library://asset/asset.JPG?id=1000000050&ext=JPG").
*/
[self getJPEGFromAssetForURL:[info objectForKey:UIImagePickerControllerReferenceURL]];
// ...
/*
* Take Asset URL and set imageJPEG property to NSData containing the
* associated JPEG, including the metadata we're after.
*/
-(void)getJPEGFromAssetForURL:(NSURL *)url {
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
[assetslibrary assetForURL:url
resultBlock: ^(ALAsset *myasset) {
ALAssetRepresentation *rep = [myasset defaultRepresentation];
#if DEBUG
NSLog(@"getJPEGFromAssetForURL: default asset representation for %@: uti: %@ size: %lld url: %@ orientation: %d scale: %f metadata: %@",
url, [rep UTI], [rep size], [rep url], [rep orientation],
[rep scale], [rep metadata]);
#endif
Byte *buf = malloc([rep size]); // will be freed automatically when associated NSData is deallocated
NSError *err = nil;
NSUInteger bytes = [rep getBytes:buf fromOffset:0LL
length:[rep size] error:&err];
if (err || bytes == 0) {
// Are err and bytes == 0 redundant? Doc says 0 return means
// error occurred which presumably means NSError is returned.
NSLog(@"error from getBytes: %@", err);
self.imageJPEG = nil;
return;
}
self.imageJPEG = [NSData dataWithBytesNoCopy:buf length:[rep size]
freeWhenDone:YES]; // YES means free malloc'ed buf that backs this when deallocated
}
failureBlock: ^(NSError *err) {
NSLog(@"can't get asset %@: %@", url, err);
}];
[assetslibrary release];
}