Problem with CGImageDestination and file naming - iphone

I am capturing images from the camera, using AVCapture as I have need of speed and the standard kit stuff is way too slow.
I have problem whereby the file that is being output (an animated GIF) is having it's file name mangles by the CGImageDestination functions...
When I output the NSURL (cast to a CFURLRef) to the log I get the path/filename I intended:
2011-09-04 20:40:25.914 Mover[3558:707] Path as string:.../Documents/91B2C5E8-F925-47F3-B539-15185F640828-3558-000003327A227485.gif
However, once the file is created and saved it actually lists the filename as this:
2011-09-04 20:40:25.960 Mover[3558:707] file: .91B2C5E8-F925-47F3-B539-15185F640828-3558-000003327A227485.gif-TtNT
See the difference? the period at the start and the 4 character suffix?
Whats really wierd is that it doesn't always do it, about 40% of the time it works OK. However it's preventing the code working further down the line where I'm listing them with previews in a table view.
Does anyone know why and how to stop it doing this?
Here's the code:
- (void)exportAnimatedGif{
NSString *guidPath = [[NSProcessInfo processInfo] globallyUniqueString];
NSString *tmpPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:guidPath];
NSString *path = [tmpPath stringByAppendingPathExtension:#"gif"];
NSLog(#"Path as string:%#", path);
CGImageDestinationRef destination = CGImageDestinationCreateWithURL((CFURLRef)[NSURL fileURLWithPath:path], kUTTypeGIF, [captureArray count], NULL);
NSDictionary *frameProperties = [NSDictionary dictionaryWithObject:[NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:testDisplay3.displayValue] forKey:(NSString *)kCGImagePropertyGIFDelayTime]
forKey:(NSString *)kCGImagePropertyGIFDictionary];
NSDictionary *gifProperties = [NSDictionary dictionaryWithObject:
[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:2], (NSString *)kCGImagePropertyGIFLoopCount,
[NSNumber numberWithFloat:testDisplay3.displayValue], (NSString*)kCGImagePropertyGIFDelayTime,
[NSNumber numberWithFloat:testDisplay3.displayValue], (NSString*)kCGImagePropertyGIFUnclampedDelayTime,
nil]
forKey:(NSString *)kCGImagePropertyGIFDictionary];
for (int ii = 0; ii < [captureArray count]; ii++)
{
UIImage *tmpImg = [[UIImage alloc] init];
tmpImg = [captureArray objectAtIndex:ii];
CGImageDestinationAddImage(destination, tmpImg.CGImage, (CFDictionaryRef)frameProperties);
}
CGImageDestinationSetProperties(destination, (CFDictionaryRef)gifProperties);
CGImageDestinationFinalize(destination);
CFRelease(destination);
//TEST OUTPUT GENERATED FILES
NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] error:nil];
for (int xx = 0; xx < [contents count]; xx++)
{
NSLog(#"file: %#", [contents objectAtIndex:xx]);
}
//END TEST CODE
[captureArray removeAllObjects];
}

AFAIK this is a temporary file that CGImageDestinationFinalize makes, the reason you see them is that CGImageDestinationFinalize failed. I think that if you check the file sizes you'll see that the ones with mangled names have a file size of 0.
I started check for succes after I got these files :)
bool success = CGImageDestinationFinalize(destination);
CFRelease(destination);
if (success) {
NSLog(#"animated GIF file created at %#", path);
} else {
NSLog(#"failed to create gif at %#", path);
}

Related

Get only image files from directory

I am storing image file in cache directory . Later I want to get all image file list from cache directory. I am using following code to get all files.
[fileManager contentsOfDirectoryAtPath:pathForCacheDirectory error:&error]
How to separate image files from this. Image file can be any format.
Thanks in advance.
// Store your supported image Extensions
NSArray *extensionList = [NSArray arrayWithObjects:#"jpg", #"jpeg", #"png", #"gif", #"bmp", nil];
// Grab the content Directory
NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:pathForCacheDirectory error:&error];
NSMutableArray *listOfImageFiles = [NSMutableArray arrayWithCapacity:0];
// Check for Images of supported type
for(NSString *filepath in contents){
if ([extensionList containsObject:[filepath pathExtension]])
{
// Found Image File
[listOfImageFiles addObject:filepath];
}
}
NSLog(#"Lisf of Image Files : %#",listOfImageFiles);
a brutal way is to enum all extensions you consider it to be an image.
a better way is using UTI, check this Get the type of a file in Cocoa
You can filter file using extensions.
NSArray *contents = [fileManager contentsOfDirectoryAtPath:pathForCacheDirectory error:&error];
for(NSString *filepath in contents){
if ([[filepath pathExtension] isEqualToString: #"png"]) {
// Your code
}
}
Try this, hope this will help.
NSArray * contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:YOURPATH error:NULL];
NSMutableArray * onlyImages = [[NSMutableArray alloc]init];
for (NSString * contentPath in contents) {
NSString * lastPath = [contentPath pathExtension];
if ([lastPath isEqualToString:#"jpg"] || [lastPath isEqualToString:#"jpeg"] || [lastPath isEqualToString:#"png"] || /* any other */ ) {
[onlyImages addObject:contentPath]; // only images
}
}
See this & check:
CFStringRef fileExtension = (CFStringRef) [file pathExtension];
CFStringRef fileUTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension, NULL);
if (UTTypeConformsTo(fileUTI, kUTTypeImage)) NSLog(#"It's an image");
else if (UTTypeConformsTo(fileUTI, kUTTypeMovie)) NSLog(#"It's a movie");
else if (UTTypeConformsTo(fileUTI, kUTTypeText)) NSLog(#"It's text");
else NSLog(#"It's audio");

Property 'jsonData' not found on object of type 'MapViewController *'

I am trying to draw the route on the graphic layer of my app application and i do not know is this the right approach to do it, or is there another way to do it? Where i am trying to use NSArray with ArgGIS to draw out the map am i have problem with it.
*edit I tried to change the NSArray back to a JSON string and try to draw it using ArcGIS with a JSON string
This is what i have done:
NSArray *BusRoute=[jsonResult objectForKey:#"BusRoute"];
int i;
int count = [BusRoute count];
for (i = 0; i < count; i++)
{
NSDictionary *dic = [BusRoute objectAtIndex: i];
NSString *Duration = [dic valueForKey:#"Duration"];
//---PATH---
NSArray *PATH = [dic valueForKey:#"PATH"];
NSLog(#"PATH = %#", PATH);
self.path = PATH;
}
NSError *writeError = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:path options:NSJSONWritingPrettyPrinted error:&writeError];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"JSON Output: %#", jsonString);
if (self.jsonString) {
// symbolize the returned route graphic
self.jsonString.routeGraphic.symbol = [self routeSymbol];
// add the route graphic to the graphic's layer
[self._graphicsLayer addGraphic:self.jsonString.routeGraphic];
// tell the graphics layer to redraw
[self._graphicsLayer dataChanged];
}
*Output for JSON string
JSON Output: [
[
"38909,35576;38872,35589;38861,35593;38848,35597;38697,35650;38695,35651;38695,35651;38609,35681;38583,35689;38553,35697;38508,35700;38476...;29560,40043"
]
]
This is a portion of the path that i have to draw on the map:
PATH = (( "38909,35576;38872,35589;38861,35593;38848,35597;38697,35650;38695,35651;38695,35651;38609,35681;38583,35689;38553,35697;38508,35700;38476,35696;38476,35696;....))
for this line self.jsonData.routeGraphic.symbol = [self routeSymbol]; i am getting an error Property 'Property 'jsonData' not found on object of type 'MapViewController *'
what should i do to solve? pls help
*How can i draw the line of the path using the NSArray and using ArcGIS?
routeGraphic property does not have any association with NSArray Class. NSArray is the Collection.
Your code is a little strange.
what is routeGrphic???
Are not you forgotten the like code below?
YourObject *object = [path objectAtIndex:index];
object.routeGraphic.symbol = [self routeSymbol];

Saving in NSDocumentDirectory uniquely

Hi Im really having a hard time saving in my NSDocumentDirectory.Im using AGImagePickerby the way. Yes I was able to save this in NSDocumentDirectory. But how to save them uniquely ( in terms of their own then converting their names into oneSlotImages) or save them with their unique IDs then load them back. Sorry Im kinda new to this UIImagePickerControllerMediaURL thing., I think that would be my solution to my other problem for not overlaping them when saving. How to save this using their unique ID, or UIImagePickerControllerMediaURL.
for (int i = 0; i < info.count; i++) {
NSLog(#"%#", [info objectAtIndex:i]);
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask ,YES );
NSString *documentsDir = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"oneSlotImages%d.png", i]];
ALAssetRepresentation *rep = [[info objectAtIndex: i] defaultRepresentation];
UIImage *image = [UIImage imageWithCGImage:[rep fullResolutionImage]];
//----resize the images
image = [self imageByScalingAndCroppingForSize:image toSize:CGSizeMake(256,256*image.size.height/image.size.width)];
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:YES];
Thanks for the help. Much Appreciated.
You could always keep a list of used names and do something like this
int i = 1;
while([listOfUsedNames containsObject:nextAvailableTile]) {
nextAvailableTitle = [kDefaultImageName stringByAppendingFormat:#" %d", i];
i++;
}
// found an unused name
The URL for each image is unique right? So we can make use of this. Convert the URL into MD5 string (which form a unique identifier for each image). And save with that name (like "MD5string.png").
Why can't we use this?
Hope this helps you.
For converting to MD5, please create a file named NSString+MD5.h and put the code
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>
#interface NSString(MD5)
- (NSString *)MD5;
#end
in it.
Then in the NSString+MD5.m,
#import "NSString+MD5.h"
#implementation NSString(MD5)
- (NSString*)MD5
{
const char *ptr = [self UTF8String];
unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH];
CC_MD5(ptr, strlen(ptr), md5Buffer);
NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
[output appendFormat:#"%02x",md5Buffer[i]];
return output;
}
#end
Import the NSString+MD5.h class where ever you want to use the MD5 function with normal NSString object.
In you code if you have the UIImagePickerControllerMediaURL string, since it is unique for every file you can convert in to MD5 String like
NSString *imgURL = [NSString stringWithString: UIImagePickerControllerMediaURL];
NSString *MD5String = [imgURL MD5];
NSString *savedImagePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.png", MD5String]];
Use that path to save your image file.
On Loading,
Convert the UIImagePickerControllerMediaURL into MD5 and check in the Documents directory for the file
// In this the UIImagePickerControllerMediaURL is the URL of media file to load
NSString *imgURL = [NSString stringWithString: UIImagePickerControllerMediaURL];
NSString *MD5String = [imgURL MD5];
NSString *savedImagePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.png", MD5String]];
Then do the checking with the fileExistsAtPath method of NSFileManager and if exists then load the file from the path. Thats it.
Note: For this you want to keep the UIImagePickerControllerMediaURL of the images you saved in documents directory locally somewhere in your app (In DB or NSUserDefaults) for make use of then at the time of loading.
Try this:
NSMutableString *imageName = [[[NSMutableString alloc] initWithCapacity:0] autorelease];
CFUUIDRef theUUID = CFUUIDCreate(kCFAllocatorDefault);
if (theUUID) {
[imageName appendString:NSMakeCollectable(CFUUIDCreateString(kCFAllocatorDefault, theUUID))];
CFRelease(theUUID);
}
[imageName appendString:#".png"];

Get Exif data from UIImage - UIImagePickerController [duplicate]

This question already has answers here:
UIImagePickerController and extracting EXIF data from existing photos
(18 answers)
Closed 7 years ago.
How can we get Exif information from UIImage selected from UIImagePickerController?
I had done much R&D for this and got many replies but still failed to implement this.
I had gone through this this and this link
Please help me to solve this problem.
Thanks in advance..
Interesting question! I came up with the following solution working for images picked from your photo library (note my code is using ARC):
Import AssetsLibrary.framework and ImageIO.framework.
Then include the needed classes inside your .h-file:
#import <AssetsLibrary/ALAsset.h>
#import <AssetsLibrary/ALAssetRepresentation.h>
#import <ImageIO/CGImageSource.h>
#import <ImageIO/CGImageProperties.h>
And put this inside your imagePickerController:didFinishPickingMediaWithInfo: delegate method:
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library assetForURL:[info objectForKey:UIImagePickerControllerReferenceURL]
resultBlock:^(ALAsset *asset) {
ALAssetRepresentation *image_representation = [asset defaultRepresentation];
// create a buffer to hold image data
uint8_t *buffer = (Byte*)malloc(image_representation.size);
NSUInteger length = [image_representation getBytes:buffer fromOffset: 0.0 length:image_representation.size error:nil];
if (length != 0) {
// buffer -> NSData object; free buffer afterwards
NSData *adata = [[NSData alloc] initWithBytesNoCopy:buffer length:image_representation.size freeWhenDone:YES];
// identify image type (jpeg, png, RAW file, ...) using UTI hint
NSDictionary* sourceOptionsDict = [NSDictionary dictionaryWithObjectsAndKeys:(id)[image_representation UTI] ,kCGImageSourceTypeIdentifierHint,nil];
// create CGImageSource with NSData
CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef) adata, (__bridge CFDictionaryRef) sourceOptionsDict);
// get imagePropertiesDictionary
CFDictionaryRef imagePropertiesDictionary;
imagePropertiesDictionary = CGImageSourceCopyPropertiesAtIndex(sourceRef,0, NULL);
// get exif data
CFDictionaryRef exif = (CFDictionaryRef)CFDictionaryGetValue(imagePropertiesDictionary, kCGImagePropertyExifDictionary);
NSDictionary *exif_dict = (__bridge NSDictionary*)exif;
NSLog(#"exif_dict: %#",exif_dict);
// save image WITH meta data
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSURL *fileURL = nil;
CGImageRef imageRef = CGImageSourceCreateImageAtIndex(sourceRef, 0, imagePropertiesDictionary);
if (![[sourceOptionsDict objectForKey:#"kCGImageSourceTypeIdentifierHint"] isEqualToString:#"public.tiff"])
{
fileURL = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/%#.%#",
documentsDirectory,
#"myimage",
[[[sourceOptionsDict objectForKey:#"kCGImageSourceTypeIdentifierHint"] componentsSeparatedByString:#"."] objectAtIndex:1]
]];
CGImageDestinationRef dr = CGImageDestinationCreateWithURL ((__bridge CFURLRef)fileURL,
(__bridge CFStringRef)[sourceOptionsDict objectForKey:#"kCGImageSourceTypeIdentifierHint"],
1,
NULL
);
CGImageDestinationAddImage(dr, imageRef, imagePropertiesDictionary);
CGImageDestinationFinalize(dr);
CFRelease(dr);
}
else
{
NSLog(#"no valid kCGImageSourceTypeIdentifierHint found …");
}
// clean up
CFRelease(imageRef);
CFRelease(imagePropertiesDictionary);
CFRelease(sourceRef);
}
else {
NSLog(#"image_representation buffer length == 0");
}
}
failureBlock:^(NSError *error) {
NSLog(#"couldn't get asset: %#", error);
}
];
One thing I noticed is, that iOS will ask the user to allow location services – if he denies, you won't be abled to get the image data …
EDIT
Added code to save the image including its meta data. It's a quick approach, so maybe there is a better way, but it works!
These answers all seem extremely complex. If the image has been saved to the Camera Roll, and you have the ALAsset (either from UIImagePicker or ALAssetLibrary) you can get the metadata like so:
asset.defaultRepresentation.metadata;
If you want to save that image from camera roll to another location (say in Sandbox/Documents) simply do:
CGImageDestinationRef imageDestinationRef = CGImageDestinationCreateWithURL((__bridge CFURLRef)urlToSaveTo, kUTTypeJPEG, 1, NULL);
CFDictionaryRef imagePropertiesRef = (__bridge CFDictionaryRef)asset.defaultRepresentation.metadata;
CGImageDestinationAddImage(imageDestinationRef, asset.defaultRepresentation.fullResolutionImage, imagePropertiesRef);
if (!CGImageDestinationFinalize(imageDestinationRef)) NSLog(#"Failed to copy photo on save to %#", urlToSaveTo);
CFRelease(imageDestinationRef);
I had found solution and got answer from here
From here We can get GPS info as well..
Amazing and thanks all for helping me to solve this problem.
UPDATE
This is another function that I had created myself, also return Exif data as well as GPS data and in this function we doesn't need any third party library.. but you have to turn on location services for this. and use current latitude and longitude for that. so have to use CoreLocation.framework
//FOR CAMERA IMAGE
-(NSMutableData *)getImageWithMetaData:(UIImage *)pImage
{
NSData* pngData = UIImagePNGRepresentation(pImage);
CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)pngData, NULL);
NSDictionary *metadata = (NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source, 0, NULL);
NSMutableDictionary *metadataAsMutable = [[metadata mutableCopy]autorelease];
[metadata release];
//For GPS Dictionary
NSMutableDictionary *GPSDictionary = [[[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyGPSDictionary]mutableCopy]autorelease];
if(!GPSDictionary)
GPSDictionary = [NSMutableDictionary dictionary];
[GPSDictionary setValue:[NSNumber numberWithDouble:currentLatitude] forKey:(NSString*)kCGImagePropertyGPSLatitude];
[GPSDictionary setValue:[NSNumber numberWithDouble:currentLongitude] forKey:(NSString*)kCGImagePropertyGPSLongitude];
NSString* ref;
if (currentLatitude <0.0)
ref = #"S";
else
ref =#"N";
[GPSDictionary setValue:ref forKey:(NSString*)kCGImagePropertyGPSLatitudeRef];
if (currentLongitude <0.0)
ref = #"W";
else
ref =#"E";
[GPSDictionary setValue:ref forKey:(NSString*)kCGImagePropertyGPSLongitudeRef];
[GPSDictionary setValue:[NSNumber numberWithFloat:location.altitude] forKey:(NSString*)kCGImagePropertyGPSAltitude];
//For EXIF Dictionary
NSMutableDictionary *EXIFDictionary = [[[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyExifDictionary]mutableCopy]autorelease];
if(!EXIFDictionary)
EXIFDictionary = [NSMutableDictionary dictionary];
[EXIFDictionary setObject:[NSDate date] forKey:(NSString*)kCGImagePropertyExifDateTimeOriginal];
[EXIFDictionary setObject:[NSDate date] forKey:(NSString*)kCGImagePropertyExifDateTimeDigitized];
//add our modified EXIF data back into the image’s metadata
[metadataAsMutable setObject:EXIFDictionary forKey:(NSString *)kCGImagePropertyExifDictionary];
[metadataAsMutable setObject:GPSDictionary forKey:(NSString *)kCGImagePropertyGPSDictionary];
CFStringRef UTI = CGImageSourceGetType(source);
NSMutableData *dest_data = [NSMutableData data];
CGImageDestinationRef destination = CGImageDestinationCreateWithData((CFMutableDataRef)dest_data, UTI, 1, NULL);
if(!destination)
dest_data = [[pngData mutableCopy] autorelease];
else
{
CGImageDestinationAddImageFromSource(destination, source, 0, (CFDictionaryRef) metadataAsMutable);
BOOL success = CGImageDestinationFinalize(destination);
if(!success)
dest_data = [[pngData mutableCopy] autorelease];
}
if(destination)
CFRelease(destination);
CFRelease(source);
return dest_data;
}
//FOR PHOTO LIBRARY IMAGE
-(NSMutableData *)getImagedataPhotoLibrary:(NSDictionary *)pImgDictionary andImage:(UIImage *)pImage
{
NSData* data = UIImagePNGRepresentation(pImage);
CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)data, NULL);
NSMutableDictionary *metadataAsMutable = [[pImgDictionary mutableCopy]autorelease];
CFStringRef UTI = CGImageSourceGetType(source);
NSMutableData *dest_data = [NSMutableData data];
//For Mutabledata
CGImageDestinationRef destination = CGImageDestinationCreateWithData((CFMutableDataRef)dest_data, UTI, 1, NULL);
if(!destination)
dest_data = [[data mutableCopy] autorelease];
else
{
CGImageDestinationAddImageFromSource(destination, source, 0, (CFDictionaryRef) metadataAsMutable);
BOOL success = CGImageDestinationFinalize(destination);
if(!success)
dest_data = [[data mutableCopy] autorelease];
}
if(destination)
CFRelease(destination);
CFRelease(source);
return dest_data;
}
and We will retrieve that data like this
//FOR CAMERA IMAGE
NSData *originalImgData = [self getImageWithMetaData:imgOriginal];
//FOR PHOTO LIBRARY IMAGE
[self getImagedataPhotoLibrary:[[myasset defaultRepresentation] metadata] andImage:imgOriginal];
For all of this you should have to Import AssetsLibrary.framework and ImageIO.framework.
I have used this method for getting the exifdata dictionary from image , I hope this will also work for you
-(void)getExifDataFromImage:(UIImage *)currentImage
{
NSData* pngData = UIImageJPEGRepresentation(currentImage, 1.0);
CGImageSourceRef mySourceRef = CGImageSourceCreateWithData((CFDataRef)pngData, NULL);
//CGImageSourceRef mySourceRef = CGImageSourceCreateWithURL((__bridge CFURLRef)myURL, NULL);
if (mySourceRef != NULL)
{
NSDictionary *myMetadata = (__bridge NSDictionary *)CGImageSourceCopyPropertiesAtIndex(mySourceRef,0,NULL);
NSDictionary *exifDic = [myMetadata objectForKey:(NSString *)kCGImagePropertyExifDictionary];
NSDictionary *tiffDic = [myMetadata objectForKey:(NSString *)kCGImagePropertyTIFFDictionary];
NSLog(#"exifDic properties: %#", myMetadata); //all data
float rawShutterSpeed = [[exifDic objectForKey:(NSString *)kCGImagePropertyExifExposureTime] floatValue];
int decShutterSpeed = (1 / rawShutterSpeed);
NSLog(#"Camera %#",[tiffDic objectForKey:(NSString *)kCGImagePropertyTIFFModel]);
NSLog(#"Focal Length %#mm",[exifDic objectForKey:(NSString *)kCGImagePropertyExifFocalLength]);
NSLog(#"Shutter Speed %#", [NSString stringWithFormat:#"1/%d", decShutterSpeed]);
NSLog(#"Aperture f/%#",[exifDic objectForKey:(NSString *)kCGImagePropertyExifFNumber]);
NSNumber *ExifISOSpeed = [[exifDic objectForKey:(NSString*)kCGImagePropertyExifISOSpeedRatings] objectAtIndex:0];
NSLog(#"ISO %ld",[ExifISOSpeed integerValue]);
NSLog(#"Taken %#",[exifDic objectForKey:(NSString*)kCGImagePropertyExifDateTimeDigitized]);
}
}
You need ALAssetsLibrary to actually retrieve the EXIF info from an image. The EXIF is added to an image only when it is saved to the Photo Library. Even if you use ALAssetLibrary to get an image asset from the library, it will lose all EXIF info if you set it to a UIImage.
I have tried to insert GPS coordinates into image metadata picked by iPad Camera as it was suggested by Mehul.
It Works, Thank you for your post.
P.S.
Who intends to use that code, just substitude the two geolocations at the top of the function -(NSMutableData *)getImageWithMetaData:(UIImage *)pImage {
double currentLatitude = [locationManager location].coordinate.latitude;
double currentLongitude = [locationManager location].coordinate.longitude;
...
By supposing that you have already initializied somewhere locationManager in your code, like this:
locationManager = [[CLLocationManager alloc] init];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[locationManager setDelegate:self]; // Not necessary in this case
[locationManager startUpdatingLocation]; // Not neccessary in this case
and by importing CoreLocation/CoreLocation.h and ImageIO/ImageIO.h headers with associated frameworks.

Problem reading a string from an NSDictionary inside an NSMutableArray stored using NSKeyedArchiver

I'm saving some data using a series of NSDictionaries, stored in an NSMutableArray and archived using NSKeyedArchiver.
I'm basically trying to save the states of several instances the class 'Brick', so I've implemented a getBlueprint method like this (slimmed down version)
-(id)getBlueprint
{
// NOTE: brickColor is a string
NSDictionary *blueprint = [NSDictionary dictionaryWithObjectsAndKeys:
brickColor, #"color",
[NSNumber numberWithInt:rotation], #"rotation",
nil];
return blueprint;
}
And so I have another method that creates a new Brick instance when provided with a blueprint.
-(id)initWithBlueprint:(NSDictionary *)blueprint spriteSheet:(NSString *)ssheet
{
if((self == [super init])){
brickColor = [blueprint objectForKey:#"color"];
[self setColorOffset:brickColor];
while(rotation != [[blueprint objectForKey:#"rotation"] intValue]){
[self setRotation:90];
}
}
return self;
}
Which works when I pass it a 'fresh' blueprint, but not when I read a blueprint from a saved file... sort of. For example, the rotation will work, but changing the color wont. So while I can read the value of brickColor using
NSLog(#"brick color %#", [blueprint objectForKey:#"color"]);
if I try something like
if(brickColor == #"purple"){
colorOffset = CGPointMake(72,36);
NSLog(#"Changed offset for -- %# -- to %#", color, NSStringFromCGPoint(colorOffset));
}
And I know that color is purple, the condition doesn't return true. I thought it might be that somehow NSKeyedUnarchiver changed a string into something else, but the following test returns true.
if([color isKindOfClass:[NSString class]]){
NSLog(#"%# IS A STRING", color);
}else{
NSLog(#"!!!!! COLOR IS A NOT STRING !!!!!");
}
As I said, this isn't a problem if I try to use a freshly created NSDictionary as a blueprint, only when a blueprint is archived and then read back in.
So, as usual, I'm wondering if anyone has any ideas why this might be happening.
incase it's relevant, here's how the data is being stored and recieved.
// Saving
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-(void)buildLevelData{
levelData = [[NSMutableArray alloc] initWithCapacity:100];
for(brickSprite *brick in spriteHolder.children){
[levelData addObject:[brick getBlueprint]];
}
}
-(void)saveLevel
{
[self buildLevelData];
NSData *rawDat = [NSKeyedArchiver archivedDataWithRootObject:levelData];
if([self writeApplicationData:rawDat toFile:saveFileName]){
NSLog(#"Data Saved");
}else{
NSLog(#"ERROR SAVING LEVEL DATA!");
}
[[Director sharedDirector] replaceScene:[MainMenu scene]];
}
- (BOOL)writeApplicationData:(NSData *)data toFile:(NSString *)fileName {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
if (!documentsDirectory) {
NSLog(#"Documents directory not found!");
return NO;
}
NSString *appFile = [saveDir stringByAppendingPathComponent:fileName];
return ([data writeToFile:appFile atomically:YES]);
}
// Loading
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
- (void) loadRandomMapFrom:(NSString *)dir
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [paths objectAtIndex:0];
if(!docsDir){
NSLog(#"Cound Not Find Documents Directory When trying To Load Random Map");
return;
}
dir = [docsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"/%#", dir]];
// we'll also set the file name here.
NSArray *existingFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dir error:nil];
// get last file for this test
NSString *filePath = [dir stringByAppendingPathComponent:[existingFiles objectAtIndex:([existingFiles count] - 1)]];
NSMutableArray *levelData = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
[self buildMapWithData:levelData];
}
-(void)buildMapWithData:(NSMutableArray *)lData
{
for(NSDictionary *blueprint in lData){
brickSprite *brick = [[brickSprite alloc] initWithBlueprint:blueprint spriteSheet:#"blocks.png"];
[spriteHolder addChild:brick];
}
}
Sorry about the mess of a question. There's a lot going on that I'm struggling to fully understand myself so it's hard to break it down to the bare minimum.
You should always compare strings with [firstString isEqualToString:secondString], because firstString == secondString only checks for pointer equality, e.g. if both strings are stored at the same location (which they'll never be when comparing dynamically created objects and string constants).