2010-10-07 7 views
12

Ich habe große Probleme beim Speichern eines Fotos in der Kamerarolle mit Geotag-Informationen auf iOS4.1. Ich verwende folgende ALAssetsLibrary API:Geotag-Info mit Foto auf iOS4.1 speichern

- (void)writeImageDataToSavedPhotosAlbum:(NSData *)imageData 
           metadata:(NSDictionary *)metadata 
         completionBlock:(ALAssetsLibraryWriteImageCompletionBlock)completionBlock 

Ich habe die GPS-Koordinaten, die ich wünsche, mit dem Foto als Eingabe zu speichern. Leider gibt es keine Dokumentation oder Beispielcode, der beschreibt, wie die Metadaten NSDictionary gebildet werden, die die GPS-Koordinaten einkapseln. Kann jemand einen Beispielcode veröffentlichen, von dem bekannt ist, dass er funktioniert?

Ich habe auch versucht, mit iPhone Exif-Bibliothek Geo-Informationen in ImageData statt Metadaten zu speichern, aber leider iPhone Exif Bibliothek stürzt ab. Jede Hilfe wird sehr geschätzt.

Antwort

2

Nach langem Suchen fand ich und angepasst diese

Damit wird cclocation Daten in eine geeignete NSDictionary

#import <ImageIO/ImageIO.h> 

+(NSMutableDictionary *)updateExif:(CLLocation *)currentLocation{ 


    NSMutableDictionary* locDict = [[NSMutableDictionary alloc] init]; 


    CLLocationDegrees exifLatitude = currentLocation.coordinate.latitude; 
    CLLocationDegrees exifLongitude = currentLocation.coordinate.longitude; 

    [locDict setObject:currentLocation.timestamp forKey:(NSString*)kCGImagePropertyGPSTimeStamp]; 

    if (exifLatitude <0.0){ 
     exifLatitude = exifLatitude*(-1); 
     [locDict setObject:@"S" forKey:(NSString*)kCGImagePropertyGPSLatitudeRef]; 
    }else{ 
     [locDict setObject:@"N" forKey:(NSString*)kCGImagePropertyGPSLatitudeRef]; 
    } 
    [locDict setObject:[NSNumber numberWithFloat:exifLatitude] forKey:(NSString*)kCGImagePropertyGPSLatitude]; 

    if (exifLongitude <0.0){ 
     exifLongitude=exifLongitude*(-1); 
     [locDict setObject:@"W" forKey:(NSString*)kCGImagePropertyGPSLongitudeRef]; 
    }else{ 
     [locDict setObject:@"E" forKey:(NSString*)kCGImagePropertyGPSLongitudeRef]; 
    } 
    [locDict setObject:[NSNumber numberWithFloat:exifLongitude] forKey:(NSString*) kCGImagePropertyGPSLongitude]; 


    return [locDict autorelease]; 

} 

Dann füge ich es auf die vorhandenen Metadaten, die Sie durch die Kamera zu bekommen (was nicht Standardmäßig haben die gPS-Daten)

ich erhalte die ursprünglichen Metadaten wie dieses

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{ 
    [imageMetaData setDictionary:[[info objectForKey:UIImagePickerControllerMediaMetadata] copy]]; 
} 

Dann füge ich das GPS-Wörterbuch, das die vorherige Methode erzeugt.

[imageMetaData setObject:currentLocation forKey:(NSString*)kCGImagePropertyGPSDictionary];   

    [library writeImageToSavedPhotosAlbum:[viewImage CGImage] metadata:imageMetaData completionBlock:photoCompblock]; 
+0

Gute Antwort, +1, aber du bist Einstellung ' kCGImagePropertyGPSTimeStamp' falsch. Der Wert muss ein NSString anstelle eines NSDate sein. – Anomie

+0

Sie müssen das Wörterbuch, das das Objekt für "UIImagePickerControllerMediaMetadata" ist, nicht "kopieren"; Wenn ein veränderbares Wörterbuch angewiesen wird, sich an ein anderes Wörterbuch anzupassen, wird das empfangende Wörterbuch geändert, sodass das Wörterbuch zur Kopie wird. Die Kopie, die Sie mit der Kopie-Nachricht machen, ist verschwendet. Schlimmer, da du es nicht loslässt, leckst du es. Sie könnten das lösen, indem Sie es freigeben oder es automatisch freigeben, aber besser nicht die unnötige Kopie an erster Stelle machen. –

23

Hier Code ist, alle verfügbaren Informationen aus einem CLLocation Objekt in das richtige Format für einen GPS-Metadaten-Wörterbuch zu kopieren:

- (NSDictionary *)getGPSDictionaryForLocation:(CLLocation *)location { 
    NSMutableDictionary *gps = [NSMutableDictionary dictionary]; 

    // GPS tag version 
    [gps setObject:@"2.2.0.0" forKey:(NSString *)kCGImagePropertyGPSVersion]; 

    // Time and date must be provided as strings, not as an NSDate object 
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 
    [formatter setDateFormat:@"HH:mm:ss.SSSSSS"]; 
    [formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; 
    [gps setObject:[formatter stringFromDate:location.timestamp] forKey:(NSString *)kCGImagePropertyGPSTimeStamp]; 
    [formatter setDateFormat:@"yyyy:MM:dd"]; 
    [gps setObject:[formatter stringFromDate:location.timestamp] forKey:(NSString *)kCGImagePropertyGPSDateStamp]; 
    [formatter release]; 

    // Latitude 
    CGFloat latitude = location.coordinate.latitude; 
    if (latitude < 0) { 
     latitude = -latitude; 
     [gps setObject:@"S" forKey:(NSString *)kCGImagePropertyGPSLatitudeRef]; 
    } else { 
     [gps setObject:@"N" forKey:(NSString *)kCGImagePropertyGPSLatitudeRef]; 
    } 
    [gps setObject:[NSNumber numberWithFloat:latitude] forKey:(NSString *)kCGImagePropertyGPSLatitude]; 

    // Longitude 
    CGFloat longitude = location.coordinate.longitude; 
    if (longitude < 0) { 
     longitude = -longitude; 
     [gps setObject:@"W" forKey:(NSString *)kCGImagePropertyGPSLongitudeRef]; 
    } else { 
     [gps setObject:@"E" forKey:(NSString *)kCGImagePropertyGPSLongitudeRef]; 
    } 
    [gps setObject:[NSNumber numberWithFloat:longitude] forKey:(NSString *)kCGImagePropertyGPSLongitude]; 

    // Altitude 
    CGFloat altitude = location.altitude; 
    if (!isnan(altitude)){ 
     if (altitude < 0) { 
      altitude = -altitude; 
      [gps setObject:@"1" forKey:(NSString *)kCGImagePropertyGPSAltitudeRef]; 
     } else { 
      [gps setObject:@"0" forKey:(NSString *)kCGImagePropertyGPSAltitudeRef]; 
     } 
     [gps setObject:[NSNumber numberWithFloat:altitude] forKey:(NSString *)kCGImagePropertyGPSAltitude]; 
    } 

    // Speed, must be converted from m/s to km/h 
    if (location.speed >= 0){ 
     [gps setObject:@"K" forKey:(NSString *)kCGImagePropertyGPSSpeedRef]; 
     [gps setObject:[NSNumber numberWithFloat:location.speed*3.6] forKey:(NSString *)kCGImagePropertyGPSSpeed]; 
    } 

    // Heading 
    if (location.course >= 0){ 
     [gps setObject:@"T" forKey:(NSString *)kCGImagePropertyGPSTrackRef]; 
     [gps setObject:[NSNumber numberWithFloat:location.course] forKey:(NSString *)kCGImagePropertyGPSTrack]; 
    } 

    return gps; 
} 

das Wörterbuch mit dieser Methode als Wert für die kCGImagePropertyGPSDictionary Schlüssel zurückgegeben zuweisen Im Metadatenwörterbuch gelangen Sie an writeImageDataToSavedPhotosAlbum:metadata:completionBlock: oder CGImageDestinationAddImage().

+1

Ich denke, du solltest Double statt Float mit Längen- und Breitengrad verwenden ... sonst könntest du mit ein paar Fuß/Meter auskommen. – Marius

+0

@Anomie, sprechen von kCGImagePropertyGPSDateStamp und kCGImagePropertyGPSTimeStamp, ist es möglich, unser eigenes Datum/Zeit hinzuzufügen, anstatt es aus "location.timestamp" zu nehmen. –

+0

@ShishirShetty: Sie könnten ein bisschen der Geolocation-Daten fälschen, wenn Sie das möchten. – Anomie