in Frameworks/ImageIO/CGImageSource.mm [703:1102]
CFDictionaryRef readJPEGProperties(IWICMetadataQueryReader* imageMetadataReader) {
PROPVARIANT propertyValue;
PropVariantInit(&propertyValue);
NSMutableDictionary* properties = [[NSMutableDictionary alloc] init];
// JPEG Properties - Common
// DPIHeight and DPIWidth are saved in different places for different image formats, and these locations only represent
// DPI if {ushort=1} is 1, otherwise they are other units.
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/{ushort=282}", &propertyValue)) && propertyValue.vt == VT_UI8) {
[properties setObject:[NSNumber numberWithDouble:(double)propertyValue.uhVal.LowPart / propertyValue.uhVal.HighPart]
forKey:(id)kCGImagePropertyDPIWidth];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/{ushort=283}", &propertyValue)) && propertyValue.vt == VT_UI8) {
[properties setObject:[NSNumber numberWithDouble:(double)propertyValue.uhVal.LowPart / propertyValue.uhVal.HighPart]
forKey:(id)kCGImagePropertyDPIHeight];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/{ushort=256}", &propertyValue)) && propertyValue.vt == VT_UI2) {
[properties setObject:[NSNumber numberWithInt:propertyValue.uiVal] forKey:(id)kCGImagePropertyPixelWidth];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/{ushort=256}", &propertyValue)) && propertyValue.vt == VT_UI4) {
[properties setObject:[NSNumber numberWithInt:propertyValue.ulVal] forKey:(id)kCGImagePropertyPixelWidth];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/{ushort=257}", &propertyValue)) && propertyValue.vt == VT_UI2) {
[properties setObject:[NSNumber numberWithInt:propertyValue.uiVal] forKey:(id)kCGImagePropertyPixelHeight];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/{ushort=257}", &propertyValue)) && propertyValue.vt == VT_UI4) {
[properties setObject:[NSNumber numberWithInt:propertyValue.ulVal] forKey:(id)kCGImagePropertyPixelHeight];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/{ushort=258}", &propertyValue)) && propertyValue.vt == VT_UI2) {
[properties setObject:[NSNumber numberWithInt:propertyValue.uiVal] forKey:(id)kCGImagePropertyDepth];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/{ushort=274}", &propertyValue)) && propertyValue.vt == VT_UI2) {
[properties setObject:[NSNumber numberWithInt:propertyValue.uiVal] forKey:(id)kCGImagePropertyOrientation];
}
// JPEG Properties - Format-specific
NSMutableDictionary* jfifProperties = [[NSMutableDictionary alloc] init];
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app0/{ushort=0}", &propertyValue)) && propertyValue.vt == VT_UI2) {
// NSArray doesn't print properly but this is how iOS does it
NSMutableArray* jfifVersionArray = [NSMutableArray array];
[jfifVersionArray addObject:[NSNumber numberWithInt:(propertyValue.uiVal >> 8) & 0xF]];
[jfifVersionArray addObject:[NSNumber numberWithInt:(propertyValue.uiVal >> 4) & 0xF]];
[jfifVersionArray addObject:[NSNumber numberWithInt:propertyValue.uiVal & 0xF]];
[jfifProperties setObject:jfifVersionArray forKey:(id)kCGImagePropertyJFIFVersion];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app0/{ushort=2}", &propertyValue)) && propertyValue.vt == VT_UI2) {
[jfifProperties setObject:[NSNumber numberWithInt:propertyValue.uiVal] forKey:(id)kCGImagePropertyJFIFXDensity];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app0/{ushort=3}", &propertyValue)) && propertyValue.vt == VT_UI2) {
[jfifProperties setObject:[NSNumber numberWithInt:propertyValue.uiVal] forKey:(id)kCGImagePropertyJFIFYDensity];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app0/{ushort=1}", &propertyValue)) && propertyValue.vt == VT_UI1) {
[jfifProperties setObject:[NSNumber numberWithInt:propertyValue.bVal] forKey:(id)kCGImagePropertyJFIFDensityUnit];
}
// Add the JFIF dictionary to the properties if there are any JFIF properties
if ([jfifProperties count] != 0) {
[properties setObject:jfifProperties forKey:(id)kCGImagePropertyJFIFDictionary];
}
CFRelease(jfifProperties);
// GPS Properties - JPEG
NSMutableDictionary* gpsProperties = [[NSMutableDictionary alloc] init];
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/gps/{ushort=6}", &propertyValue)) && propertyValue.vt == VT_UI8) {
[gpsProperties setObject:[NSNumber numberWithDouble:(double)propertyValue.uhVal.LowPart / propertyValue.uhVal.HighPart]
forKey:(id)kCGImagePropertyGPSAltitude];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/gps/{ushort=5}", &propertyValue)) && propertyValue.vt == VT_UI1) {
[gpsProperties setObject:[NSNumber numberWithInt:propertyValue.bVal] forKey:(id)kCGImagePropertyGPSAltitudeRef];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/gps/{ushort=29}", &propertyValue)) && propertyValue.vt == VT_LPSTR) {
[gpsProperties setObject:[NSString stringWithUTF8String:propertyValue.pszVal] forKey:(id)kCGImagePropertyGPSDateStamp];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/gps/{ushort=11}", &propertyValue)) && propertyValue.vt == VT_UI8) {
[gpsProperties setObject:[NSNumber numberWithDouble:(double)propertyValue.uhVal.LowPart / propertyValue.uhVal.HighPart]
forKey:(id)kCGImagePropertyGPSDOP];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/gps/{ushort=17}", &propertyValue)) && propertyValue.vt == VT_UI8) {
[gpsProperties setObject:[NSNumber numberWithDouble:(double)propertyValue.uhVal.LowPart / propertyValue.uhVal.HighPart]
forKey:(id)kCGImagePropertyGPSImgDirection];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/gps/{ushort=16}", &propertyValue)) && propertyValue.vt == VT_LPSTR) {
[gpsProperties setObject:[NSString stringWithUTF8String:propertyValue.pszVal] forKey:(id)kCGImagePropertyGPSImgDirectionRef];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/gps/{ushort=2}", &propertyValue)) &&
propertyValue.vt == (VT_VECTOR | VT_UI8)) {
if (propertyValue.caub.cElems == 3) { // Validate number of fields
double degreesPart = (double)propertyValue.cauh.pElems[0].LowPart / propertyValue.cauh.pElems[0].HighPart;
double minutesPart = (double)propertyValue.cauh.pElems[1].LowPart / propertyValue.cauh.pElems[1].HighPart;
double secondsPart = (double)propertyValue.cauh.pElems[2].LowPart / propertyValue.cauh.pElems[2].HighPart;
[gpsProperties
setObject:[NSNumber numberWithDouble:degreesPart + minutesPart / c_minutesPerDegree + secondsPart / (c_secondsPerDegree)]
forKey:(id)kCGImagePropertyGPSLatitude];
}
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/gps/{ushort=1}", &propertyValue)) && propertyValue.vt == VT_LPSTR) {
[gpsProperties setObject:[NSString stringWithUTF8String:propertyValue.pszVal] forKey:(id)kCGImagePropertyGPSLatitudeRef];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/gps/{ushort=4}", &propertyValue)) &&
propertyValue.vt == (VT_VECTOR | VT_UI8)) {
if (propertyValue.caub.cElems == 3) { // Validate number of fields
double degreesPart = (double)propertyValue.cauh.pElems[0].LowPart / propertyValue.cauh.pElems[0].HighPart;
double minutesPart = (double)propertyValue.cauh.pElems[1].LowPart / propertyValue.cauh.pElems[1].HighPart;
double secondsPart = (double)propertyValue.cauh.pElems[2].LowPart / propertyValue.cauh.pElems[2].HighPart;
[gpsProperties
setObject:[NSNumber numberWithDouble:degreesPart + minutesPart / c_minutesPerDegree + secondsPart / (c_secondsPerDegree)]
forKey:(id)kCGImagePropertyGPSLongitude];
}
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/gps/{ushort=3}", &propertyValue)) && propertyValue.vt == VT_LPSTR) {
[gpsProperties setObject:[NSString stringWithUTF8String:propertyValue.pszVal] forKey:(id)kCGImagePropertyGPSLongitudeRef];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/gps/{ushort=13}", &propertyValue)) && propertyValue.vt == VT_UI8) {
[gpsProperties setObject:[NSNumber numberWithDouble:(double)propertyValue.uhVal.LowPart / propertyValue.uhVal.HighPart]
forKey:(id)kCGImagePropertyGPSSpeed];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/gps/{ushort=12}", &propertyValue)) && propertyValue.vt == VT_LPSTR) {
[gpsProperties setObject:[NSString stringWithUTF8String:propertyValue.pszVal] forKey:(id)kCGImagePropertyGPSSpeedRef];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/gps/{ushort=7}", &propertyValue)) &&
propertyValue.vt == (VT_VECTOR | VT_UI8)) {
double timeStampHours = (double)propertyValue.cauh.pElems[0].LowPart / propertyValue.cauh.pElems[0].HighPart;
double timeStampMinutes = (double)propertyValue.cauh.pElems[1].LowPart / propertyValue.cauh.pElems[1].HighPart;
double timeStampSeconds = (double)propertyValue.cauh.pElems[2].LowPart / propertyValue.cauh.pElems[2].HighPart;
[gpsProperties setObject:[NSString stringWithFormat:@"%.2d:%.2d:%.2f", (int)timeStampHours, (int)timeStampMinutes, timeStampSeconds]
forKey:(id)kCGImagePropertyGPSTimeStamp];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/gps/{ushort=15}", &propertyValue)) && propertyValue.vt == VT_UI8) {
[gpsProperties setObject:[NSNumber numberWithDouble:(double)propertyValue.uhVal.LowPart / propertyValue.uhVal.HighPart]
forKey:(id)kCGImagePropertyGPSTrack];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/gps/{ushort=14}", &propertyValue)) && propertyValue.vt == VT_LPSTR) {
[gpsProperties setObject:[NSString stringWithUTF8String:propertyValue.pszVal] forKey:(id)kCGImagePropertyGPSTrackRef];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/gps/{ushort=0}", &propertyValue)) &&
propertyValue.vt == (VT_VECTOR | VT_UI1)) {
if (propertyValue.caub.cElems == 4) {
NSMutableArray* gpsVersionArray = [NSMutableArray array];
for (int index = 0; index < 4; index++) {
[gpsVersionArray addObject:[NSNumber numberWithInt:propertyValue.caub.pElems[index]]];
}
[gpsProperties setObject:gpsVersionArray forKey:(id)kCGImagePropertyGPSVersion];
}
}
// Add the GPS dictionary to the properties if there are any GPS properties
if ([gpsProperties count] != 0) {
[properties setObject:gpsProperties forKey:(id)kCGImagePropertyGPSDictionary];
}
CFRelease(gpsProperties);
// Exif Properties - JPEG
NSMutableDictionary* exifProperties = [[NSMutableDictionary alloc] init];
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=40962}", &propertyValue)) && propertyValue.vt == VT_UI2) {
// iOS can get both the general image dimension properties as well as Exif ones from this value
[exifProperties setObject:[NSNumber numberWithInt:propertyValue.uiVal] forKey:(id)kCGImagePropertyExifPixelXDimension];
[properties setObject:[NSNumber numberWithInt:propertyValue.uiVal] forKey:(id)kCGImagePropertyPixelWidth];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=40962}", &propertyValue)) && propertyValue.vt == VT_UI4) {
[exifProperties setObject:[NSNumber numberWithInt:propertyValue.ulVal] forKey:(id)kCGImagePropertyExifPixelXDimension];
[properties setObject:[NSNumber numberWithInt:propertyValue.ulVal] forKey:(id)kCGImagePropertyPixelWidth];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=40963}", &propertyValue)) && propertyValue.vt == VT_UI2) {
[exifProperties setObject:[NSNumber numberWithInt:propertyValue.uiVal] forKey:(id)kCGImagePropertyExifPixelYDimension];
[properties setObject:[NSNumber numberWithInt:propertyValue.uiVal] forKey:(id)kCGImagePropertyPixelHeight];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=40963}", &propertyValue)) && propertyValue.vt == VT_UI4) {
[exifProperties setObject:[NSNumber numberWithInt:propertyValue.ulVal] forKey:(id)kCGImagePropertyExifPixelYDimension];
[properties setObject:[NSNumber numberWithInt:propertyValue.ulVal] forKey:(id)kCGImagePropertyPixelHeight];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=33434}", &propertyValue)) && propertyValue.vt == VT_UI8) {
[exifProperties setObject:[NSNumber numberWithDouble:(double)propertyValue.uhVal.LowPart / propertyValue.uhVal.HighPart]
forKey:(id)kCGImagePropertyExifExposureTime];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=37378}", &propertyValue)) && propertyValue.vt == VT_UI8) {
[exifProperties setObject:[NSNumber numberWithDouble:(double)propertyValue.uhVal.LowPart / propertyValue.uhVal.HighPart]
forKey:(id)kCGImagePropertyExifApertureValue];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=37379}", &propertyValue)) && propertyValue.vt == VT_UI8) {
[exifProperties setObject:[NSNumber numberWithDouble:(double)propertyValue.uhVal.LowPart / propertyValue.uhVal.HighPart]
forKey:(id)kCGImagePropertyExifBrightnessValue];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=36868}", &propertyValue)) &&
propertyValue.vt == VT_LPSTR) {
[exifProperties setObject:[NSString stringWithUTF8String:propertyValue.pszVal] forKey:(id)kCGImagePropertyExifDateTimeDigitized];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=36867}", &propertyValue)) &&
propertyValue.vt == VT_LPSTR) {
[exifProperties setObject:[NSString stringWithUTF8String:propertyValue.pszVal] forKey:(id)kCGImagePropertyExifDateTimeOriginal];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=41988}", &propertyValue)) && propertyValue.vt == VT_UI8) {
[exifProperties setObject:[NSNumber numberWithDouble:(double)propertyValue.uhVal.LowPart / propertyValue.uhVal.HighPart]
forKey:(id)kCGImagePropertyExifDigitalZoomRatio];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=41986}", &propertyValue)) && propertyValue.vt == VT_UI2) {
[exifProperties setObject:[NSNumber numberWithInt:propertyValue.uiVal] forKey:(id)kCGImagePropertyExifExposureMode];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=34850}", &propertyValue)) && propertyValue.vt == VT_UI2) {
[exifProperties setObject:[NSNumber numberWithInt:propertyValue.uiVal] forKey:(id)kCGImagePropertyExifExposureProgram];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=37385}", &propertyValue)) && propertyValue.vt == VT_UI2) {
[exifProperties setObject:[NSNumber numberWithInt:propertyValue.uiVal] forKey:(id)kCGImagePropertyExifFlash];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=33437}", &propertyValue)) && propertyValue.vt == VT_UI8) {
[exifProperties setObject:[NSNumber numberWithDouble:(double)propertyValue.uhVal.LowPart / propertyValue.uhVal.HighPart]
forKey:(id)kCGImagePropertyExifFNumber];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=37386}", &propertyValue)) && propertyValue.vt == VT_UI8) {
[exifProperties setObject:[NSNumber numberWithDouble:(double)propertyValue.uhVal.LowPart / propertyValue.uhVal.HighPart]
forKey:(id)kCGImagePropertyExifFocalLength];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=34867}", &propertyValue)) && propertyValue.vt == VT_UI4) {
[exifProperties setObject:[NSNumber numberWithInt:propertyValue.ulVal] forKey:(id)kCGImagePropertyExifISOSpeedRatings];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=42035}", &propertyValue)) &&
propertyValue.vt == VT_LPSTR) {
[exifProperties setObject:[NSString stringWithUTF8String:propertyValue.pszVal] forKey:(id)kCGImagePropertyExifLensMake];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=42036}", &propertyValue)) &&
propertyValue.vt == VT_LPSTR) {
[exifProperties setObject:[NSString stringWithUTF8String:propertyValue.pszVal] forKey:(id)kCGImagePropertyExifLensModel];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=37500}", &propertyValue)) &&
propertyValue.vt == VT_BLOB) {
[exifProperties setObject:[NSData dataWithBytes:propertyValue.blob.pBlobData length:propertyValue.blob.cbSize]
forKey:(id)kCGImagePropertyExifMakerNote];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=37383}", &propertyValue)) && propertyValue.vt == VT_UI2) {
[exifProperties setObject:[NSNumber numberWithInt:propertyValue.uiVal] forKey:(id)kCGImagePropertyExifMeteringMode];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=41990}", &propertyValue)) && propertyValue.vt == VT_UI2) {
[exifProperties setObject:[NSNumber numberWithInt:propertyValue.uiVal] forKey:(id)kCGImagePropertyExifSceneCaptureType];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=37377}", &propertyValue)) && propertyValue.vt == VT_I8) {
[exifProperties setObject:[NSNumber numberWithDouble:(double)propertyValue.hVal.LowPart / propertyValue.hVal.HighPart]
forKey:(id)kCGImagePropertyExifShutterSpeedValue];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=37510}", &propertyValue)) &&
propertyValue.vt == VT_LPWSTR) {
[exifProperties setObject:[[NSString alloc] initWithBytes:propertyValue.pwszVal
length:wcslen(propertyValue.pwszVal) * sizeof(wchar_t)
encoding:NSUnicodeStringEncoding]
forKey:(id)kCGImagePropertyExifUserComment];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=36864}", &propertyValue)) &&
propertyValue.vt == VT_BLOB) {
NSData* exifVersion = [NSData dataWithBytesNoCopy:propertyValue.blob.pBlobData length:propertyValue.blob.cbSize freeWhenDone:YES];
NSMutableArray* exifVersionArray = [NSMutableArray array];
char* exifVersionCharacters = (char*)[exifVersion bytes];
[exifVersionArray addObject:[NSNumber numberWithInt:exifVersionCharacters[1] - '0']];
[exifVersionArray addObject:[NSNumber numberWithInt:exifVersionCharacters[2] - '0']];
[exifVersionArray addObject:[NSNumber numberWithInt:exifVersionCharacters[3] - '0']];
[exifProperties setObject:exifVersionArray forKey:(id)kCGImagePropertyExifVersion];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/exif/{ushort=41987}", &propertyValue)) && propertyValue.vt == VT_UI2) {
[exifProperties setObject:[NSNumber numberWithInt:propertyValue.uiVal] forKey:(id)kCGImagePropertyExifWhiteBalance];
}
// Add the Exif dictionary to the properties if there are any Exif properties
if ([exifProperties count] != 0) {
[properties setObject:exifProperties forKey:(id)kCGImagePropertyExifDictionary];
}
CFRelease(exifProperties);
// The following properties are in TIFF property dictionary, but for /app1/ifd/, which is not a TIFF directory
// This information gets read for JPEG files on iOS, and do in fact get added to a TIFF dictionary, even for a JPEG
NSMutableDictionary* tiffProperties = [[NSMutableDictionary alloc] init];
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/{ushort=274}", &propertyValue)) && propertyValue.vt == VT_UI2) {
[tiffProperties setObject:[NSNumber numberWithInt:propertyValue.uiVal] forKey:(id)kCGImagePropertyTIFFOrientation];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/{ushort=282}", &propertyValue)) && propertyValue.vt == VT_UI8) {
[tiffProperties setObject:[NSNumber numberWithDouble:(double)propertyValue.uhVal.LowPart / propertyValue.uhVal.HighPart]
forKey:(id)kCGImagePropertyTIFFXResolution];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/{ushort=283}", &propertyValue)) && propertyValue.vt == VT_UI8) {
[tiffProperties setObject:[NSNumber numberWithDouble:(double)propertyValue.uhVal.LowPart / propertyValue.uhVal.HighPart]
forKey:(id)kCGImagePropertyTIFFYResolution];
}
PropVariantClear(&propertyValue);
if (SUCCEEDED(imageMetadataReader->GetMetadataByName(L"/app1/ifd/{ushort=296}", &propertyValue)) && propertyValue.vt == VT_UI2) {
[tiffProperties setObject:[NSNumber numberWithInt:propertyValue.uiVal] forKey:(id)kCGImagePropertyTIFFResolutionUnit];
}
// Add the TIFF dictionary to the properties if there are any TIFF properties
if ([tiffProperties count] != 0) {
[properties setObject:tiffProperties forKey:(id)kCGImagePropertyTIFFDictionary];
}
CFRelease(tiffProperties);
return (CFDictionaryRef)properties;
}