Original Problem
I am trying to save an image into the camera roll while preserving all the original EXIF/JFIF data. I'd like the image as saved to the camera roll to be identical to the original file byte-for-byte. When I save the image via [ALAssetsLibrary writeImageDataToSavedPhotosAlbum:metadata:completionBlock:]
, the original EXIF data is preserved, but JFIF is stripped out.
ALAssetsLibrary *library = [[[ALAssetsLibrary alloc] init] autorelease];
[library writeImageDataToSavedPhotosAlbum:imageData metadata:nil completionBlock:^(NSURL *assetURL, NSError *error) {
[self imageDidFinishSavingToCameraRollWithError:error];
}];
I tried using the iphone-exif project to parse out the JFIF data and explicitly pass it in via the metadata parameter:
EXFJpeg *jpegScanner = [[EXFJpeg alloc] init];
[jpegScanner scanImageData:imageData];
EXFJFIF *jfif = [jpegScanner jfif];
NSMutableDictionary *jfifMetadata = [[NSMutableDictionary alloc] init];
[jfifMetadata setObject:[jfif version] forKey:(NSString *)kCGImagePropertyJFIFVersion];
...
NSMutableDictionary *metadata = [[NSMutableDictionary alloc] init];
[metadata setObject:jfifMetadata forKey:(NSString*)kCGImagePropertyJFIFDictionary];
But doing so results in the same file, byte-for-byte, as passing a nil
metadata dictionary, meaning the JFIF data is still being stripped by iOS.
According to Wikipedia:
Formally, the Exif and JFIF standards are incompatible. This is because both specify that their particular application segment (APP0 for JFIF, APP1 for Exif) must be the first in the image file. In practice, many programs and digital cameras produce files with both application segments included. This will not affect the image decoding for most decoders, but poorly designed JFIF or Exif parsers may not recognise the file properly.
Is there any way to save the original file to the camera roll byte-for-byte, or will iOS always ignore JFIF data if EXIF is present?
Update: 2/26/13
I've filed <rdar://13291591>
with Apple. I also created a sample project demonstrating the issue: http://spolet.to/3J0l1u3w0R2e
The sample app has three buttons: one for a JPEG with JFIF data, one for a JPEG without JFIF data, and one for a PNG. When the button is tapped, the corresponding image will be hashed and saved to the photo library. The resulting ALAsset will then be hashed as well.
Results:
- The ALAsset for the saved PNG has the same hash as the original file.
- The ALAssets for the saved JPEGs do not have the same hashes as their original counterparts.
Digging in to this, it appears that the 'Brightness Value', 'Components Configuration', 'Thumbnail Length' and 'Thumbnail Image' attributes within the ALAsset EXIF data have been modified by the OS. Further, the original JFIF data (for the image with JFIF) has been stripped.
Expected Results:
- All three files should have the same hash when saved into the photo library.