Reputation: 183
I want to display image metadata using ios. Meta data like Aperture, Shutterspeed, Exposure Compensation, ISO, Lens Focal Length, etc. So please help me if anybody has idea.
Upvotes: 17
Views: 27354
Reputation: 10005
CGImageSourceRef source = CGImageSourceCreateWithURL( (CFURLRef) aUrl, NULL);
CGImageSourceRef source = CGImageSourceCreateWithData( (CFDataRef) theData, NULL);
NSDictionary* metadata = (NSDictionary *)CFBridgingRelease(CGImageSourceCopyPropertiesAtIndex(source,0,NULL));
CFRelease(source);
Check the dictionary contents here.
Upvotes: 30
Reputation: 209
Here is a sample code that helps us in reading the Aperture, Shutterspeed, Exposure Compensation, ISO, Lens, Focal Length etc and converts it into dictionary format.
Consider all the following functions of a single class
guard let imageSource = CGImageSourceCreateWithURL(fileURL as CFURL, nil),
let metadata = CGImageSourceCopyMetadataAtIndex(imageSource, 0, nil),
let tags = CGImageMetadataCopyTags(metadata),
let imageInfo = self.readMetadataTagArr(tagArr: tags) else { return }
Then there are a few helper functions that actually do all the hardwork to extract/convert the data into dictionary format.
/// Reads the Arrays of tags and convert them into a dictionary of [String: Any]
private static func readMetadataTagArr(tagArr: CFArray) -> [String: Any]? {
var result = [String: Any]()
for (_, tag) in (tagArr as NSArray).enumerated() {
let tagMetadata = tag as! CGImageMetadataTag
if let cfName = CGImageMetadataTagCopyName(tagMetadata) {
let name = String(cfName)
result[name] = self.readMetadataTag(metadataTag: tagMetadata)
}
}
return result
}
/// convert CGImageMetadataTag to a dictionary of [String: Any]
private static func readMetadataTag(metadataTag: CGImageMetadataTag) -> [String: Any] {
var result = [String: Any]()
guard let cfName = CGImageMetadataTagCopyName(metadataTag) else { return result }
let name = String(cfName)
let value = CGImageMetadataTagCopyValue(metadataTag)
/// checking the type of `value` object and then performing respective operation on `value`
if CFGetTypeID(value) == CFStringGetTypeID() {
let valueStr = String(value as! CFString)
result[name] = valueStr
} else if CFGetTypeID(value) == CFDictionaryGetTypeID() {
let nsDict: NSDictionary = value as! CFDictionary
result[name] = self.getDictionary(from: nsDict)
} else if CFGetTypeID(value) == CFArrayGetTypeID() {
let valueArr: NSArray = value as! CFArray
for (_, item) in valueArr.enumerated() {
let tagMetadata = item as! CGImageMetadataTag
result[name] = self.readMetadataTag(metadataTag: tagMetadata)
}
} else {
// when the data was of some other type
let descriptionString: CFString = CFCopyDescription(value);
let str = String(descriptionString)
result[name] = str
}
return result
}
/// Converting CGImage Metadata dictionary to [String: Any]
private static func getDictionary(from nsDict: NSDictionary) -> [String: Any] {
var subDictionary = [String: Any]()
for (key, val) in nsDict {
guard let key = key as? String else { continue }
let tempDict: [String: Any] = [key: val]
if JSONSerialization.isValidJSONObject(tempDict) {
subDictionary[key] = val
} else {
let mData = val as! CGImageMetadataTag
let tempDict: [String: Any] = [key: self.readMetadataTag(metadataTag: mData)]
if JSONSerialization.isValidJSONObject(tempDict) {
subDictionary[key] = tempDict
}
}
}
return subDictionary
}
Here is the list of all dictionary keys extracted
Here are some sample dictionary values such as FocalLength, ApertureValue, LensSpecification etc
LensModel, ShutterSpeedValue etc
Upvotes: 0
Reputation: 4082
Reading image properties via Core Graphics wrapped as Swift struct:
struct ImageMetadata {
var imageProperties : [CFString: Any]
init?(data: Data) {
let options = [kCGImageSourceShouldCache: kCFBooleanFalse]
if let imageSource = CGImageSourceCreateWithData(data as CFData, options as CFDictionary),
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [CFString: Any] {
self.imageProperties = imageProperties
} else {
return nil
}
}
var dpi : Int? { imageProperties[kCGImagePropertyDPIWidth] as? Int }
var width : Int? { imageProperties[kCGImagePropertyPixelWidth] as? Int }
var height : Int? { imageProperties[kCGImagePropertyPixelHeight] as? Int }
}
Upvotes: 2
Reputation: 1170
updated to iOS 11 with photos framework
Objective - C:
#import <Photos/Photos.h>
- (void)imagePickerController:(UIImagePickerController *)imagePicker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
PHAsset* asset = info[UIImagePickerControllerPHAsset];
[asset requestContentEditingInputWithOptions:nil completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {
CIImage *fullImage = [CIImage imageWithContentsOfURL:contentEditingInput.fullSizeImageURL];
NSLog(@"%@", fullImage.properties.description);
}];
[imagePicker dismissViewControllerAnimated:YES completion:nil];
}
You also need the permission of Photo library Usage (NSPhotoLibraryUsageDescription) and then can add the following code to view did load or view did appear
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
switch (status) {
case PHAuthorizationStatusAuthorized:
NSLog(@"PHAuthorizationStatusAuthorized");
break;
case PHAuthorizationStatusDenied:
NSLog(@"PHAuthorizationStatusDenied");
break;
case PHAuthorizationStatusNotDetermined:
NSLog(@"PHAuthorizationStatusNotDetermined");
break;
case PHAuthorizationStatusRestricted:
NSLog(@"PHAuthorizationStatusRestricted");
break;
}
}];
Upvotes: 1
Reputation: 2227
Answering my own question. The memory-effective and fast way to get a GPS metadata is
let options = [kCGImageSourceShouldCache as String: kCFBooleanFalse]
if let data = NSData(contentsOfURL: url), imgSrc = CGImageSourceCreateWithData(data, options) {
let metadata = CGImageSourceCopyPropertiesAtIndex(imgSrc, 0, options) as Dictionary
let gpsData = metadata[kCGImagePropertyGPSDictionary] as? [String : AnyObject]
}
The second option is
if let img = CIImage(contentsOfURL: url), metadata = img.properties(),
gpsData = metadata[kCGImagePropertyGPSDictionary] as? [String : AnyObject] { … }
it looks nicer in Swift but uses more memory (tested via Profiler).
Upvotes: 0
Reputation: 1828
swift 4
static func imageDataProperties(_ imageData: Data) -> NSDictionary? {
if let imageSource = CGImageSourceCreateWithData(imageData as CFData, nil)
{
if let dictionary = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) {
return dictionary
}
}
return nil
}
Upvotes: 5
Reputation: 3081
Here is code, to get meta data from an image path:
NSData *imagedata = [NSData dataWithContentsOfFile:imagePath];
CGImageSourceRef source = CGImageSourceCreateWithData((CFMutableDataRef)imagedata, NULL);
NSDictionary *metadata = [(NSDictionary *)CGImageSourceCopyPropertiesAtIndex(source,0,NULL)autorelease];
Or, if using swift 4.0:
var imagedata = Data(contentsOfFile: imagePath)
var source: CGImageSourceRef = CGImageSourceCreateWithData((imagedata as? CFMutableDataRef), nil)
var metadata = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as? [AnyHashable: Any]
Upvotes: 14
Reputation: 1067
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSURL *referenceURL = [info objectForKey:UIImagePickerControllerReferenceURL];
if(referenceURL) {
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library assetForURL:referenceURL resultBlock:^(ALAsset *asset) {
ALAssetRepresentation *rep = [asset defaultRepresentation];
NSDictionary *metadata = rep.metadata;
NSLog(@"image data %@", metadata);
} failureBlock:^(NSError *error) {
// error handling
}];
}
Upvotes: 0
Reputation: 7574
Here is what I'm using to get the image size:
+ (CGSize) sizeOfImage:(NSString *) fileName withPath: (NSURL *) fullDirectoryPath;
{
NSURL *imageNameWithPath = [NSURL URLWithString:fileName relativeToURL:fullDirectoryPath];
CGImageSourceRef source = CGImageSourceCreateWithURL( (CFURLRef) imageNameWithPath, NULL);
if (!source) return CGSizeZero;
CFDictionaryRef dictRef = CGImageSourceCopyPropertiesAtIndex(source,0,NULL);
NSDictionary* metadata = (__bridge NSDictionary *)dictRef;
NSLog(@"metadata= %@", metadata);
CGSize result = CGSizeZero;
CGFloat width = [metadata[@"PixelWidth"] floatValue];
CGFloat height = [metadata[@"PixelHeight"] floatValue];
NSLog(@"width= %f, height= %f", width, height);
// The orientation in the metadata does *not* map to UIImageOrientation. Rather, see: https://developer.apple.com/library/ios/documentation/GraphicsImaging/Reference/CGImageProperties_Reference/index.html#//apple_ref/doc/constant_group/Individual_Image_Properties
// This idea of orientation seems a little odd to me, but it seems it translates to even numbers need to be switched in width/height, odd numbers do not.
NSUInteger orientation = [metadata[@"Orientation"] integerValue];
switch (orientation) {
// Comments give "Location of the origin of the image"
case 1: // Top, left
case 3: // Bottom, right
case 5: // Left, top
case 7: // Right, bottom
result = CGSizeMake(width, height);
break;
case 2: // Top, right
case 4: // Bottom, left
case 6: // Right, top
case 8: // Left, bottom
result = CGSizeMake(height, width);
break;
default:
NSAssert(NO, @"Should not get to here!");
break;
}
CFRelease(source);
NSLog(@"size: %@, orientation: %d", NSStringFromCGSize(result), orientation);
return result;
}
/* Example meta data:
ColorModel = RGB;
Depth = 8;
Orientation = 6;
PixelHeight = 1936;
PixelWidth = 2592;
"{Exif}" = {
ColorSpace = 1;
PixelXDimension = 2592;
PixelYDimension = 1936;
};
"{JFIF}" = {
DensityUnit = 0;
JFIFVersion = (
1,
1
);
XDensity = 1;
YDensity = 1;
};
"{TIFF}" = {
Orientation = 6;
};
}
*/
Upvotes: 0
Reputation: 8347
You need to use assets library to read exif metadata of image.
#import <AssetsLibrary/AssetsLibrary.h>
And then add following code :
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSURL *assetURL = [info objectForKey:UIImagePickerControllerReferenceURL];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
__block NSMutableDictionary *imageMetadata = nil;
[library assetForURL:assetURL
resultBlock:^(ALAsset *asset) {
NSDictionary *metadata = asset.defaultRepresentation.metadata;
imageMetadata = [[NSMutableDictionary alloc] initWithDictionary:metadata];
NSLog(@"%@",imageMetadata.description);
}
failureBlock:^(NSError *error) {
}];
}
Hope this will help
Upvotes: -2