2010-10-07 2 views
12

Je rencontre des problèmes majeurs lors de la sauvegarde d'une photo sur un appareil photo avec des informations de géolocalisation sur iOS4.1. J'utilise l'API suivant ALAssetsLibrary:Enregistrement d'informations de géolocalisation avec la photo sur iOS4.1

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

J'ai les coordonnées GPS que je souhaite enregistrer avec la photo comme entrée. Malheureusement, il n'y a pas de documentation ou d'exemple de code qui décrit comment former la méta-donnée NSDictionary qui encapsule les coordonnées GPS. Quelqu'un peut-il poster un exemple de code connu pour fonctionner?

J'ai également essayé d'utiliser la bibliothèque iPhone Exif pour enregistrer des informations géographiques dans imageData plutôt que d'utiliser des métadonnées, mais malheureusement, la bibliothèque de l'iPhone Exif plante. Toute aide est grandement appréciée.

Répondre

2

Après de longues recherches, j'ai trouvé et adapté cette

Cela transforme les données cclocation dans un récipient approprié 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]; 

} 

Puis je l'ajoute aux métadonnées existantes que vous obtenez à travers la caméra (qui ne par défaut ont les données GPS)

Je reçois les métadonnées d'origine comme celui-ci

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

puis j'ajoute le dictionnaire gps que la méthode précédente produit.

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

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

Bonne réponse, +1, mais vous configurez ' kCGImagePropertyGPSTimeStamp' erroné. La valeur doit être un NSString plutôt qu'un NSDate. – Anomie

+0

Vous n'avez pas besoin de copier le dictionnaire qui est l'objet de 'UIImagePickerControllerMediaMetadata'; Dire à un dictionnaire mutable de se définir pour correspondre à un autre dictionnaire modifiera le dictionnaire de réception, de sorte que le dictionnaire devienne la copie. La copie que vous faites avec le message 'copy' est gaspillée; pire, puisque vous ne le relâchez pas, vous le fuyez. Vous pouvez résoudre cela en le relâchant ou en le libérant automatiquement, mais mieux vaut ne pas faire la copie inutile en premier lieu. –

23

Voici le code pour copier toutes les informations disponibles à partir d'un objet CLLocation dans le format approprié pour un dictionnaire de métadonnées GPS:

- (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; 
} 

Attribuer le dictionnaire retourné par cette méthode que la valeur de la clé kCGImagePropertyGPSDictionary Dans le dictionnaire des métadonnées, vous passez à writeImageDataToSavedPhotosAlbum:metadata:completionBlock: ou CGImageDestinationAddImage().

+1

Je pense que vous devriez utiliser Double au lieu de Float avec la latitude et la longitude ... sinon vous pourriez être dehors avec quelques pieds/mètres. – Marius

+0

@Anomie, en parlant de kCGImagePropertyGPSDateStamp et de kCGImagePropertyGPSTimeStamp, est-il possible d'ajouter notre propre date/heure, au lieu de la prendre de "location.timestamp".? –

+0

@ShishirShetty: Vous pouvez truquer n'importe quel bit des données de géolocalisation, si c'est ce que vous voulez faire. – Anomie

Questions connexes